home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / Perl / toke.c < prev    next >
Text File  |  1994-01-01  |  63KB  |  2,811 lines

  1. /* $RCSfile: toke.c,v $$Revision: 4.0.1.9 $$Date: 1993/02/05 19:48:43 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of the Perl Artistic License,
  6.  *    as specified in the README file.
  7.  *
  8.  * $Log:    toke.c,v $
  9.  * Revision 4.0.1.9  1993/02/05  19:48:43  lwall
  10.  * patch36: now detects ambiguous use of filetest operators as well as unary
  11.  * patch36: fixed ambiguity on - within tr///
  12.  * 
  13.  * Revision 4.0.1.8  1992/06/23  12:33:45  lwall
  14.  * patch35: bad interaction between backslash and hyphen in tr///
  15.  * 
  16.  * Revision 4.0.1.7  92/06/11  21:16:30  lwall
  17.  * patch34: expectterm incorrectly set to indicate start of program or block
  18.  * 
  19.  * Revision 4.0.1.6  92/06/08  16:03:49  lwall
  20.  * patch20: an EXPR may now start with a bareword
  21.  * patch20: print $fh EXPR can now expect term rather than operator in EXPR
  22.  * patch20: added ... as variant on ..
  23.  * patch20: new warning on spurious backslash
  24.  * patch20: new warning on missing $ for foreach variable
  25.  * patch20: "foo"x1024 now legal without space after x
  26.  * patch20: new warning on print accidentally used as function
  27.  * patch20: tr/stuff// wasn't working right
  28.  * patch20: 2. now eats the dot
  29.  * patch20: <@ARGV> now notices @ARGV
  30.  * patch20: tr/// now lets you say \-
  31.  * 
  32.  * Revision 4.0.1.5  91/11/11  16:45:51  lwall
  33.  * patch19: default arg for shift was wrong after first subroutine definition
  34.  * 
  35.  * Revision 4.0.1.4  91/11/05  19:02:48  lwall
  36.  * patch11: \x and \c were subject to double interpretation in regexps
  37.  * patch11: prepared for ctype implementations that don't define isascii()
  38.  * patch11: nested list operators could miscount parens
  39.  * patch11: once-thru blocks didn't display right in the debugger
  40.  * patch11: sort eval "whatever" didn't work
  41.  * patch11: underscore is now allowed within literal octal and hex numbers
  42.  * 
  43.  * Revision 4.0.1.3  91/06/10  01:32:26  lwall
  44.  * patch10: m'$foo' now treats string as single quoted
  45.  * patch10: certain pattern optimizations were botched
  46.  * 
  47.  * Revision 4.0.1.2  91/06/07  12:05:56  lwall
  48.  * patch4: new copyright notice
  49.  * patch4: debugger lost track of lines in eval
  50.  * patch4: //o and s///o now optimize themselves fully at runtime
  51.  * patch4: added global modifier for pattern matches
  52.  * 
  53.  * Revision 4.0.1.1  91/04/12  09:18:18  lwall
  54.  * patch1: perl -de "print" wouldn't stop at the first statement
  55.  * 
  56.  * Revision 4.0  91/03/20  01:42:14  lwall
  57.  * 4.0 baseline.
  58.  * 
  59.  */
  60.  
  61. #include "EXTERN.h"
  62. #include "perl.h"
  63.  
  64. #ifdef I_FCNTL
  65. #include <fcntl.h>
  66. #endif
  67. #ifdef I_SYS_FILE
  68. #include <sys/file.h>
  69. #endif
  70.  
  71. #include "perly.h"
  72.  
  73. static void set_csh();
  74.  
  75. #ifdef f_next
  76. #undef f_next
  77. #endif
  78.  
  79. /* which backslash sequences to keep in m// or s// */
  80.  
  81. static char *patleave = "\\.^$@dDwWsSbB+*?|()-nrtfeaxc0123456789[{]}";
  82.  
  83. char *reparse;        /* if non-null, scanident found ${foo[$bar]} */
  84.  
  85. void checkcomma();
  86.  
  87. #ifdef CLINE
  88. #undef CLINE
  89. #endif
  90. #define CLINE (cmdline = (curcmd->c_line < cmdline ? curcmd->c_line : cmdline))
  91.  
  92. #ifdef atarist
  93. #define PERL_META(c) ((c) | 128)
  94. #else
  95. #define META(c) ((c) | 128)
  96. #endif
  97.  
  98. #define RETURN(retval) return (bufptr = s,(int)retval)
  99. #define OPERATOR(retval) return (expectterm = TRUE,bufptr = s,(int)retval)
  100. #define TERM(retval) return (CLINE, expectterm = FALSE,bufptr = s,(int)retval)
  101. #define LOOPX(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)LOOPEX)
  102. #define FTST(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)FILETEST)
  103. #define FUN0(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC0)
  104. #define FUN1(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC1)
  105. #define FUN2(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2)
  106. #define FUN2x(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC2x)
  107. #define FUN3(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC3)
  108. #define FUN4(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC4)
  109. #define FUN5(f) return(yylval.ival = f,expectterm = FALSE,bufptr = s,(int)FUNC5)
  110. #define FL(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST)
  111. #define FL2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FLIST2)
  112. #define HFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)HSHFUN)
  113. #define HFUN3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)HSHFUN3)
  114. #define LFUN(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LVALFUN)
  115. #define AOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)ADDOP)
  116. #define MOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)MULOP)
  117. #define EOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)EQOP)
  118. #define ROP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)RELOP)
  119. #define FOP(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP)
  120. #define FOP2(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP2)
  121. #define FOP3(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP3)
  122. #define FOP4(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP4)
  123. #define FOP22(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP22)
  124. #define FOP25(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FILOP25)
  125.  
  126. #ifdef macintosh
  127. #define CHOOS(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)CHOOSE)
  128. #define MIN1(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FMIN1)
  129. #define FUN12(f) return(yylval.ival=f,expectterm = FALSE,bufptr = s,(int)FUNC12)
  130. #endif
  131.  
  132. static char *last_uni;
  133.  
  134. /* This bit of chicanery makes a unary function followed by
  135.  * a parenthesis into a function with one argument, highest precedence.
  136.  */
  137. #define UNI(f) return(yylval.ival = f, \
  138.     expectterm = TRUE, \
  139.     bufptr = s, \
  140.     last_uni = oldbufptr, \
  141.     (*s == '(' || (s = skipspace(s), *s == '(') ? (int)FUNC1 : (int)UNIOP) )
  142.  
  143. /* This does similarly for list operators, merely by pretending that the
  144.  * paren came before the listop rather than after.
  145.  */
  146. #ifdef atarist
  147. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  148.     (*s = (char) PERL_META('('), bufptr = oldbufptr, '(') : \
  149.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  150. #else
  151. #define LOP(f) return(CLINE, *s == '(' || (s = skipspace(s), *s == '(') ? \
  152.     (*s = (char) META('('), bufptr = oldbufptr, '(') : \
  153.     (yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP))
  154. #endif
  155. /* grandfather return to old style */
  156. #define OLDLOP(f) return(yylval.ival=f,expectterm = TRUE,bufptr = s,(int)LISTOP)
  157.  
  158. char *
  159. skipspace(s)
  160. register char *s;
  161. {
  162.     while (s < bufend && isSPACE(*s))
  163.     s++;
  164.     return s;
  165. }
  166.  
  167. void
  168. check_uni() {
  169.     char *s;
  170.     char ch;
  171.  
  172.     if (oldoldbufptr != last_uni)
  173.     return;
  174.     while (isSPACE(*last_uni))
  175.     last_uni++;
  176.     for (s = last_uni; isALNUM(*s) || *s == '-'; s++) ;
  177.     ch = *s;
  178.     *s = '\0';
  179.     warn("Warning: Use of \"%s\" without parens is ambiguous", last_uni);
  180.     *s = ch;
  181. }
  182.  
  183. #ifdef CRIPPLED_CC
  184.  
  185. #undef UNI
  186. #undef LOP
  187. #define UNI(f) return uni(f,s)
  188. #define LOP(f) return lop(f,s)
  189.  
  190. int
  191. uni(f,s)
  192. int f;
  193. char *s;
  194. {
  195.     yylval.ival = f;
  196.     expectterm = TRUE;
  197.     bufptr = s;
  198.     last_uni = oldbufptr;
  199.     if (*s == '(')
  200.     return FUNC1;
  201.     s = skipspace(s);
  202.     if (*s == '(')
  203.     return FUNC1;
  204.     else
  205.     return UNIOP;
  206. }
  207.  
  208. int
  209. lop(f,s)
  210. int f;
  211. char *s;
  212. {
  213.     CLINE;
  214.     if (*s != '(')
  215.     s = skipspace(s);
  216.     if (*s == '(') {
  217. #ifdef atarist
  218.     *s = PERL_META('(');
  219. #else
  220.     *s = META('(');
  221. #endif
  222.     bufptr = oldbufptr;
  223.     return '(';
  224.     }
  225.     else {
  226.     yylval.ival=f;
  227.     expectterm = TRUE;
  228.     bufptr = s;
  229.     return LISTOP;
  230.     }
  231. }
  232.  
  233. #endif /* CRIPPLED_CC */
  234.  
  235. int
  236. yylex()
  237. {
  238.     register char *s = bufptr;
  239.     register char *d;
  240.     register int tmp;
  241.     extern int yychar;        /* last token */
  242.     static bool in_format = FALSE;
  243.     static bool firstline = TRUE;
  244.  
  245.     oldoldbufptr = oldbufptr;
  246.     oldbufptr = s;
  247.  
  248.   retry:
  249. #ifdef YYDEBUG
  250.     if (debug & 1)
  251. #ifdef macintosh
  252.     if (index(s,'\n'))
  253.         fprintf(perldbg,"Tokener at %s",s);
  254.     else
  255.         fprintf(perldbg,"Tokener at %s\n",s);
  256. #else
  257.     if (index(s,'\n'))
  258.         fprintf(stderr,"Tokener at %s",s);
  259.     else
  260.         fprintf(stderr,"Tokener at %s\n",s);
  261. #endif
  262. #endif
  263. #ifdef macintosh
  264.      /* Ignore option-space */
  265.     if ((unsigned char) *s == 0312)
  266.          *s    =    ' ';
  267. #endif
  268. #ifdef BADSWITCH
  269.     if (*s & 128) {
  270.     if ((*s & 127) == '(') {
  271.         *s++ = '(';
  272.         oldbufptr = s;
  273.     }
  274.     else if ((*s & 127) == '}') {
  275.         *s++ = '}';
  276.         RETURN('}');
  277.     }
  278.     else
  279.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  280.     goto retry;
  281.     }
  282. #endif
  283.     switch (*s) {
  284.     default:
  285.     if ((*s & 127) == '(') {
  286.         *s++ = '(';
  287.         oldbufptr = s;
  288.     }
  289.     else if ((*s & 127) == '}') {
  290.         *s++ = '}';
  291.         RETURN('}');
  292.     }
  293.     else
  294.         warn("Unrecognized character \\%03o ignored", *s++ & 255);
  295.     goto retry;
  296. #ifdef macintosh
  297.     case 1:    /* MPW C preprocessor seems to insert these to mark token boundaries */
  298.         ++s;    /* Ignore them                                  */
  299.     goto retry;
  300. #endif
  301.     case 4:
  302.     case 26:
  303.     goto fake_eof;            /* emulate EOF on ^D or ^Z */
  304.     case 0:
  305.     if (!rsfp)
  306.         RETURN(0);
  307.     if (s++ < bufend)
  308.         goto retry;            /* ignore stray nulls */
  309.     last_uni = 0;
  310.     if (firstline) {
  311.         firstline = FALSE;
  312.         if (minus_n || minus_p || perldb) {
  313.         str_set(linestr,"");
  314.         if (perldb) {
  315.             char *getenv();
  316.             char *pdb = getenv("PERLDB");
  317.  
  318.             str_cat(linestr, pdb ? pdb : "require 'perldb.pl'");
  319.             str_cat(linestr, ";");
  320.         }
  321.         if (minus_n || minus_p) {
  322.             str_cat(linestr,"line: while (<>) {");
  323.             if (minus_l)
  324.             str_cat(linestr,"chop;");
  325.             if (minus_a)
  326.             str_cat(linestr,"@F=split(' ');");
  327.         }
  328.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  329.         bufend = linestr->str_ptr + linestr->str_cur;
  330.         goto retry;
  331.         }
  332.     }
  333.     if (in_format) {
  334.         bufptr = bufend;
  335.         yylval.formval = load_format();
  336.         in_format = FALSE;
  337.         oldoldbufptr = oldbufptr = s = str_get(linestr) + 1;
  338.         bufend = linestr->str_ptr + linestr->str_cur;
  339.         OPERATOR(FORMLIST);
  340.     }
  341. #ifdef macintosh
  342.         SpinMacCursor();
  343. #endif
  344.     curcmd->c_line++;
  345. #ifdef CRYPTSCRIPT
  346.     cryptswitch();
  347. #endif /* CRYPTSCRIPT */
  348.     do {
  349.         if ((s = str_gets(linestr, rsfp, 0)) == Nullch) {
  350.           fake_eof:
  351.         if (rsfp) {
  352.             if (preprocess)
  353.             (void)mypclose(rsfp);
  354.             else if ((FILE*)rsfp == stdin)
  355.             clearerr(stdin);
  356.             else
  357.             (void)fclose(rsfp);
  358.             rsfp = Nullfp;
  359.         }
  360.         if (minus_n || minus_p) {
  361.             str_set(linestr,minus_p ? ";}continue{print" : "");
  362.             str_cat(linestr,";}");
  363.             oldoldbufptr = oldbufptr = s = str_get(linestr);
  364.             bufend = linestr->str_ptr + linestr->str_cur;
  365.             minus_n = minus_p = 0;
  366.             goto retry;
  367.         }
  368.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  369.         str_set(linestr,"");
  370.         RETURN(';');    /* not infinite loop because rsfp is NULL now */
  371.         }
  372.         if (doextract && *linestr->str_ptr == '#')
  373.         doextract = FALSE;
  374.     } while (doextract);
  375.     oldoldbufptr = oldbufptr = bufptr = s;
  376.     if (perldb) {
  377.         STR *str = Str_new(85,0);
  378.  
  379.         str_sset(str,linestr);
  380.         astore(stab_xarray(curcmd->c_filestab),(int)curcmd->c_line,str);
  381.     }
  382. #ifdef DEBUG
  383.     if (firstline) {
  384.         char *showinput();
  385.         s = showinput();
  386.     }
  387. #endif
  388.     bufend = linestr->str_ptr + linestr->str_cur;
  389.     if (curcmd->c_line == 1) {
  390. #ifdef macintosh
  391.         curcmd->c_line += extract_offset;
  392. #endif
  393.         if (*s == '#' && s[1] == '!') {
  394.         if (!in_eval && !instr(s,"perl") && instr(origargv[0],"perl")) {
  395.             char **newargv;
  396.             char *cmd;
  397.  
  398.             s += 2;
  399.             if (*s == ' ')
  400.             s++;
  401.             cmd = s;
  402.             while (s < bufend && !isSPACE(*s))
  403.             s++;
  404.             *s++ = '\0';
  405.             while (s < bufend && isSPACE(*s))
  406.             s++;
  407.             if (s < bufend) {
  408.             Newz(899,newargv,origargc+3,char*);
  409.             newargv[1] = s;
  410.             while (s < bufend && !isSPACE(*s))
  411.                 s++;
  412.             *s = '\0';
  413.             Copy(origargv+1, newargv+2, origargc+1, char*);
  414.             }
  415.             else
  416.             newargv = origargv;
  417.             newargv[0] = cmd;
  418.             execv(cmd,newargv);
  419.             fatal("Can't exec %s", cmd);
  420.         }
  421.         }
  422.         else {
  423.         while (s < bufend && isSPACE(*s))
  424.             s++;
  425.         if (*s == ':')    /* for csh's that have to exec sh scripts */
  426.             s++;
  427.         }
  428.     }
  429.     goto retry;
  430.     case ' ': case '\t': case '\f': case '\r': case 013:
  431.     s++;
  432.     goto retry;
  433.     case '#':
  434.     if (preprocess && s == str_get(linestr) &&
  435.            s[1] == ' ' && (isDIGIT(s[2]) || strnEQ(s+2,"line ",5)) ) {
  436.         while (*s && !isDIGIT(*s))
  437.         s++;
  438.         curcmd->c_line = atoi(s)-1;
  439.         while (isDIGIT(*s))
  440.         s++;
  441.         d = bufend;
  442.         while (s < d && isSPACE(*s)) s++;
  443.         s[strlen(s)-1] = '\0';    /* wipe out newline */
  444.         if (*s == '"') {
  445.         s++;
  446.         s[strlen(s)-1] = '\0';    /* wipe out trailing quote */
  447.         }
  448.         if (*s)
  449.         curcmd->c_filestab = fstab(s);
  450.         else
  451.         curcmd->c_filestab = fstab(origfilename);
  452.         oldoldbufptr = oldbufptr = s = str_get(linestr);
  453.     }
  454.     /* FALL THROUGH */
  455.     case '\n':
  456.     if (in_eval && !rsfp) {
  457.         d = bufend;
  458.         while (s < d && *s != '\n')
  459.         s++;
  460.         if (s < d)
  461.         s++;
  462.         if (in_format) {
  463.         bufptr = s;
  464.         yylval.formval = load_format();
  465.         in_format = FALSE;
  466.         oldoldbufptr = oldbufptr = s = bufptr + 1;
  467.         TERM(FORMLIST);
  468.         }
  469.         curcmd->c_line++;
  470.     }
  471.     else {
  472.         *s = '\0';
  473.         bufend = s;
  474.     }
  475.     goto retry;
  476.     case '-':
  477.     if (s[1] && isALPHA(s[1]) && !isALPHA(s[2])) {
  478.         s++;
  479.         last_uni = oldbufptr;
  480.         switch (*s++) {
  481.         case 'r': FTST(O_FTEREAD);
  482.         case 'w': FTST(O_FTEWRITE);
  483.         case 'x': FTST(O_FTEEXEC);
  484.         case 'o': FTST(O_FTEOWNED);
  485.         case 'R': FTST(O_FTRREAD);
  486.         case 'W': FTST(O_FTRWRITE);
  487.         case 'X': FTST(O_FTREXEC);
  488.         case 'O': FTST(O_FTROWNED);
  489.         case 'e': FTST(O_FTIS);
  490.         case 'z': FTST(O_FTZERO);
  491.         case 's': FTST(O_FTSIZE);
  492.         case 'f': FTST(O_FTFILE);
  493.         case 'd': FTST(O_FTDIR);
  494.         case 'l': FTST(O_FTLINK);
  495.         case 'p': FTST(O_FTPIPE);
  496.         case 'S': FTST(O_FTSOCK);
  497.         case 'u': FTST(O_FTSUID);
  498.         case 'g': FTST(O_FTSGID);
  499.         case 'k': FTST(O_FTSVTX);
  500.         case 'b': FTST(O_FTBLK);
  501.         case 'c': FTST(O_FTCHR);
  502.         case 't': FTST(O_FTTTY);
  503.         case 'T': FTST(O_FTTEXT);
  504.         case 'B': FTST(O_FTBINARY);
  505.         case 'M': stabent("\024",TRUE); FTST(O_FTMTIME);
  506.         case 'A': stabent("\024",TRUE); FTST(O_FTATIME);
  507.         case 'C': stabent("\024",TRUE); FTST(O_FTCTIME);
  508.         default:
  509.         s -= 2;
  510.         break;
  511.         }
  512.     }
  513.     tmp = *s++;
  514.     if (*s == tmp) {
  515.         s++;
  516.         RETURN(DEC);
  517.     }
  518.     if (expectterm) {
  519.         if (isSPACE(*s) || !isSPACE(*bufptr))
  520.         check_uni();
  521.         OPERATOR('-');
  522.     }
  523.     else
  524.         AOP(O_SUBTRACT);
  525.     case '+':
  526.     tmp = *s++;
  527.     if (*s == tmp) {
  528.         s++;
  529.         RETURN(INC);
  530.     }
  531.     if (expectterm) {
  532.         if (isSPACE(*s) || !isSPACE(*bufptr))
  533.         check_uni();
  534.         OPERATOR('+');
  535.     }
  536.     else
  537.         AOP(O_ADD);
  538.  
  539.     case '*':
  540.     if (expectterm) {
  541.         check_uni();
  542.         s = scanident(s,bufend,tokenbuf);
  543.         yylval.stabval = stabent(tokenbuf,TRUE);
  544.         TERM(STAR);
  545.     }
  546.     tmp = *s++;
  547.     if (*s == tmp) {
  548.         s++;
  549.         OPERATOR(POW);
  550.     }
  551.     MOP(O_MULTIPLY);
  552.     case '%':
  553.     if (expectterm) {
  554.         if (!isALPHA(s[1]))
  555.         check_uni();
  556.         s = scanident(s,bufend,tokenbuf);
  557.         yylval.stabval = hadd(stabent(tokenbuf,TRUE));
  558.         TERM(HSH);
  559.     }
  560.     s++;
  561.     MOP(O_MODULO);
  562.  
  563.     case '^':
  564.     case '~':
  565.     case '(':
  566.     case ',':
  567.     case ':':
  568.     case '[':
  569.     tmp = *s++;
  570.     OPERATOR(tmp);
  571.     case '{':
  572.     tmp = *s++;
  573.     yylval.ival = curcmd->c_line;
  574.     if (isSPACE(*s) || *s == '#')
  575.         cmdline = NOLINE;   /* invalidate current command line number */
  576.     expectterm = 2;
  577.     RETURN(tmp);
  578.     case ';':
  579.     if (curcmd->c_line < cmdline)
  580.         cmdline = curcmd->c_line;
  581.     tmp = *s++;
  582.     OPERATOR(tmp);
  583.     case ')':
  584.     case ']':
  585.     tmp = *s++;
  586.     TERM(tmp);
  587.     case '}':
  588.     *s |= 128;
  589.     RETURN(';');
  590.     case '&':
  591.     s++;
  592.     tmp = *s++;
  593.     if (tmp == '&')
  594.         OPERATOR(ANDAND);
  595.     s--;
  596.     if (expectterm) {
  597.         d = bufend;
  598.         while (s < d && isSPACE(*s))
  599.         s++;
  600.         if (isALPHA(*s) || *s == '_' || *s == '\'')
  601.         *(--s) = '\\';    /* force next ident to WORD */
  602.         else
  603.         check_uni();
  604.         OPERATOR(AMPER);
  605.     }
  606.     OPERATOR('&');
  607.     case '|':
  608.     s++;
  609.     tmp = *s++;
  610.     if (tmp == '|')
  611.         OPERATOR(OROR);
  612.     s--;
  613.     OPERATOR('|');
  614.     case '=':
  615.     s++;
  616.     tmp = *s++;
  617.     if (tmp == '=')
  618.         EOP(O_EQ);
  619.     if (tmp == '~')
  620.         OPERATOR(MATCH);
  621.     s--;
  622.     OPERATOR('=');
  623.     case '!':
  624.     s++;
  625.     tmp = *s++;
  626.     if (tmp == '=')
  627.         EOP(O_NE);
  628.     if (tmp == '~')
  629.         OPERATOR(NMATCH);
  630.     s--;
  631.     OPERATOR('!');
  632.     case '<':
  633.     if (expectterm) {
  634.         if (s[1] != '<' && !index(s,'>'))
  635.         check_uni();
  636.         s = scanstr(s, SCAN_DEF);
  637.         TERM(RSTRING);
  638.     }
  639.     s++;
  640.     tmp = *s++;
  641.     if (tmp == '<')
  642.         OPERATOR(LS);
  643.     if (tmp == '=') {
  644.         tmp = *s++;
  645.         if (tmp == '>')
  646.         EOP(O_NCMP);
  647.         s--;
  648.         ROP(O_LE);
  649.     }
  650.     s--;
  651.     ROP(O_LT);
  652.     case '>':
  653.     s++;
  654.     tmp = *s++;
  655.     if (tmp == '>')
  656.         OPERATOR(RS);
  657.     if (tmp == '=')
  658.         ROP(O_GE);
  659.     s--;
  660.     ROP(O_GT);
  661.  
  662. #define SNARFWORD \
  663.     d = tokenbuf; \
  664.     while (isALNUM(*s) || *s == '\'') \
  665.         *d++ = *s++; \
  666.     while (d[-1] == '\'') \
  667.         d--,s--; \
  668.     *d = '\0'; \
  669.     d = tokenbuf;
  670.  
  671.     case '$':
  672.     if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_')) {
  673.         s++;
  674.         s = scanident(s,bufend,tokenbuf);
  675.         yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  676.         TERM(ARYLEN);
  677.     }
  678.     d = s;
  679.     s = scanident(s,bufend,tokenbuf);
  680.     if (reparse) {        /* turn ${foo[bar]} into ($foo[bar]) */
  681.       do_reparse:
  682.         s[-1] = ')';
  683.         s = d;
  684.         s[1] = s[0];
  685.         s[0] = '(';
  686.         goto retry;
  687.     }
  688.     yylval.stabval = stabent(tokenbuf,TRUE);
  689.     expectterm = FALSE;
  690.     if (isSPACE(*s) && oldoldbufptr && oldoldbufptr < bufptr) {
  691.         s++;
  692.         while (isSPACE(*oldoldbufptr))
  693.         oldoldbufptr++;
  694.         if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5)) {
  695.         if (index("&*<%", *s) && isALPHA(s[1]))
  696.             expectterm = TRUE;        /* e.g. print $fh &sub */
  697.         else if (*s == '.' && isDIGIT(s[1]))
  698.             expectterm = TRUE;        /* e.g. print $fh .3 */
  699.         else if (index("/?-+", *s) && !isSPACE(s[1]))
  700.             expectterm = TRUE;        /* e.g. print $fh -1 */
  701.         }
  702.     }
  703.     RETURN(REG);
  704.  
  705.     case '@':
  706.     d = s;
  707.     s = scanident(s,bufend,tokenbuf);
  708.     if (reparse)
  709.         goto do_reparse;
  710.     yylval.stabval = aadd(stabent(tokenbuf,TRUE));
  711.     TERM(ARY);
  712.  
  713.     case '/':            /* may either be division or pattern */
  714.     case '?':            /* may either be conditional or pattern */
  715.     if (expectterm) {
  716.         check_uni();
  717.         s = scanpat(s);
  718.         TERM(PATTERN);
  719.     }
  720.     tmp = *s++;
  721.     if (tmp == '/')
  722.         MOP(O_DIVIDE);
  723.     OPERATOR(tmp);
  724.  
  725.     case '.':
  726.     if (!expectterm || !isDIGIT(s[1])) {
  727.         tmp = *s++;
  728.         if (*s == tmp) {
  729.         s++;
  730.         if (*s == tmp) {
  731.             s++;
  732.             yylval.ival = 0;
  733.         }
  734.         else
  735.             yylval.ival = AF_COMMON;
  736.         OPERATOR(DOTDOT);
  737.         }
  738.         if (expectterm)
  739.         check_uni();
  740.         AOP(O_CONCAT);
  741.     }
  742.     /* FALL THROUGH */
  743.     case '0': case '1': case '2': case '3': case '4':
  744.     case '5': case '6': case '7': case '8': case '9':
  745.     case '\'': case '"': case '`':
  746.     s = scanstr(s, SCAN_DEF);
  747.     TERM(RSTRING);
  748.  
  749.     case '\\':    /* some magic to force next word to be a WORD */
  750.     s++;    /* used by do and sub to force a separate namespace */
  751.     if (!isALPHA(*s) && *s != '_' && *s != '\'') {
  752.         warn("Spurious backslash ignored");
  753.         goto retry;
  754.     }
  755.     /* FALL THROUGH */
  756.     case '_':
  757.     SNARFWORD;
  758.     if (d[1] == '_') {
  759.         if (strEQ(d,"__LINE__") || strEQ(d,"__FILE__")) {
  760.         ARG *arg = op_new(1);
  761.  
  762.         yylval.arg = arg;
  763.         arg->arg_type = O_ITEM;
  764.         if (d[2] == 'L')
  765.             (void)sprintf(tokenbuf,"%ld",(long)curcmd->c_line);
  766.         else
  767.             strcpy(tokenbuf, stab_val(curcmd->c_filestab)->str_ptr);
  768.         arg[1].arg_type = A_SINGLE;
  769.         arg[1].arg_ptr.arg_str = str_make(tokenbuf,strlen(tokenbuf));
  770.         TERM(RSTRING);
  771.         }
  772.         else if (strEQ(d,"__END__")) {
  773.         STAB *stab;
  774.         int fd;
  775.  
  776.         /*SUPPRESS 560*/
  777.         if (!in_eval && (stab = stabent("DATA",FALSE))) {
  778.             stab->str_pok |= SP_MULTI;
  779.             if (!stab_io(stab))
  780.             stab_io(stab) = stio_new();
  781.             stab_io(stab)->ifp = rsfp;
  782. #if defined(HAS_FCNTL) && defined(F_SETFD)
  783.             fd = fileno(rsfp);
  784.             fcntl(fd,F_SETFD,fd >= 3);
  785. #endif
  786.             if (preprocess)
  787.             stab_io(stab)->type = '|';
  788.             else if ((FILE*)rsfp == stdin)
  789.             stab_io(stab)->type = '-';
  790.             else
  791.             stab_io(stab)->type = '<';
  792.             rsfp = Nullfp;
  793.         }
  794.         goto fake_eof;
  795.         }
  796.     }
  797.     break;
  798.     case 'a': case 'A':
  799.     SNARFWORD;
  800.     if (strEQ(d,"alarm"))
  801.         UNI(O_ALARM);
  802.     if (strEQ(d,"accept"))
  803.         FOP22(O_ACCEPT);
  804. #ifdef macintosh
  805.     if (strEQ(d,"answer"))
  806.         MIN1(O_ANSWER);
  807.     if (strEQ(d,"ask"))
  808.         FUN12(O_ASK);
  809. #endif
  810.     if (strEQ(d,"atan2"))
  811.         FUN2(O_ATAN2);
  812.     break;
  813.     case 'b': case 'B':
  814.     SNARFWORD;
  815.     if (strEQ(d,"bind"))
  816.         FOP2(O_BIND);
  817.     if (strEQ(d,"binmode"))
  818.         FOP(O_BINMODE);
  819.     break;
  820.     case 'c': case 'C':
  821.     SNARFWORD;
  822.     if (strEQ(d,"chop"))
  823.         LFUN(O_CHOP);
  824.     if (strEQ(d,"continue"))
  825.         OPERATOR(CONTINUE);
  826.     if (strEQ(d,"chdir")) {
  827.         (void)stabent("ENV",TRUE);    /* may use HOME */
  828.         UNI(O_CHDIR);
  829.     }
  830.     if (strEQ(d,"close"))
  831.         FOP(O_CLOSE);
  832.     if (strEQ(d,"closedir"))
  833.         FOP(O_CLOSEDIR);
  834.     if (strEQ(d,"cmp"))
  835.         EOP(O_SCMP);
  836.     if (strEQ(d,"caller"))
  837.         UNI(O_CALLER);
  838.     if (strEQ(d,"crypt")) {
  839. #ifdef FCRYPT
  840.         static int cryptseen = 0;
  841.  
  842.         if (!cryptseen++)
  843.         init_des();
  844. #endif
  845.         FUN2(O_CRYPT);
  846.     }
  847.     if (strEQ(d,"chmod"))
  848.         LOP(O_CHMOD);
  849.     if (strEQ(d,"chown"))
  850.         LOP(O_CHOWN);
  851.     if (strEQ(d,"connect"))
  852.         FOP2(O_CONNECT);
  853.     if (strEQ(d,"cos"))
  854.         UNI(O_COS);
  855.     if (strEQ(d,"chroot"))
  856.         UNI(O_CHROOT);
  857. #ifdef macintosh
  858.     if (strEQ(d,"choose"))
  859.         CHOOS(O_CHOOSE);
  860. #endif
  861.     break;
  862.     case 'd': case 'D':
  863.     SNARFWORD;
  864.     if (strEQ(d,"do")) {
  865.         d = bufend;
  866.         while (s < d && isSPACE(*s))
  867.         s++;
  868.         if (isALPHA(*s) || *s == '_')
  869.         *(--s) = '\\';    /* force next ident to WORD */
  870.         OPERATOR(DO);
  871.     }
  872.     if (strEQ(d,"die"))
  873.         LOP(O_DIE);
  874.     if (strEQ(d,"defined"))
  875.         LFUN(O_DEFINED);
  876.     if (strEQ(d,"delete"))
  877.         OPERATOR(DELETE);
  878.     if (strEQ(d,"dbmopen"))
  879.         HFUN3(O_DBMOPEN);
  880.     if (strEQ(d,"dbmclose"))
  881.         HFUN(O_DBMCLOSE);
  882.     if (strEQ(d,"dump"))
  883.         LOOPX(O_DUMP);
  884.     break;
  885.     case 'e': case 'E':
  886.     SNARFWORD;
  887.     if (strEQ(d,"else"))
  888.         OPERATOR(ELSE);
  889.     if (strEQ(d,"elsif")) {
  890.         yylval.ival = curcmd->c_line;
  891.         OPERATOR(ELSIF);
  892.     }
  893.     if (strEQ(d,"eq") || strEQ(d,"EQ"))
  894.         EOP(O_SEQ);
  895.     if (strEQ(d,"exit"))
  896.         UNI(O_EXIT);
  897.     if (strEQ(d,"eval")) {
  898.         allstabs = TRUE;        /* must initialize everything since */
  899.         UNI(O_EVAL);        /* we don't know what will be used */
  900.     }
  901.     if (strEQ(d,"eof"))
  902.         FOP(O_EOF);
  903.     if (strEQ(d,"exp"))
  904.         UNI(O_EXP);
  905.     if (strEQ(d,"each"))
  906.         HFUN(O_EACH);
  907.     if (strEQ(d,"exec")) {
  908.         set_csh();
  909.         LOP(O_EXEC_OP);
  910.     }
  911.     if (strEQ(d,"endhostent"))
  912.         FUN0(O_EHOSTENT);
  913.     if (strEQ(d,"endnetent"))
  914.         FUN0(O_ENETENT);
  915.     if (strEQ(d,"endservent"))
  916.         FUN0(O_ESERVENT);
  917.     if (strEQ(d,"endprotoent"))
  918.         FUN0(O_EPROTOENT);
  919.     if (strEQ(d,"endpwent"))
  920.         FUN0(O_EPWENT);
  921.     if (strEQ(d,"endgrent"))
  922.         FUN0(O_EGRENT);
  923.     break;
  924.     case 'f': case 'F':
  925.     SNARFWORD;
  926.     if (strEQ(d,"for") || strEQ(d,"foreach")) {
  927.         yylval.ival = curcmd->c_line;
  928.         while (s < bufend && isSPACE(*s))
  929.         s++;
  930.         if (isALPHA(*s))
  931.         fatal("Missing $ on loop variable");
  932.         OPERATOR(FOR);
  933.     }
  934.     if (strEQ(d,"format")) {
  935.         d = bufend;
  936.         while (s < d && isSPACE(*s))
  937.         s++;
  938.         if (isALPHA(*s) || *s == '_')
  939.         *(--s) = '\\';    /* force next ident to WORD */
  940.         in_format = TRUE;
  941.         allstabs = TRUE;        /* must initialize everything since */
  942.         OPERATOR(FORMAT);        /* we don't know what will be used */
  943.     }
  944.     if (strEQ(d,"fork"))
  945.         FUN0(O_FORK);
  946.     if (strEQ(d,"fcntl"))
  947.         FOP3(O_FCNTL);
  948.     if (strEQ(d,"fileno"))
  949.         FOP(O_FILENO);
  950.     if (strEQ(d,"flock"))
  951.         FOP2(O_FLOCK);
  952.     break;
  953.     case 'g': case 'G':
  954.     SNARFWORD;
  955.     if (strEQ(d,"gt") || strEQ(d,"GT"))
  956.         ROP(O_SGT);
  957.     if (strEQ(d,"ge") || strEQ(d,"GE"))
  958.         ROP(O_SGE);
  959.     if (strEQ(d,"grep"))
  960.         FL2(O_GREP);
  961.     if (strEQ(d,"goto"))
  962.         LOOPX(O_GOTO);
  963.     if (strEQ(d,"gmtime"))
  964.         UNI(O_GMTIME);
  965.     if (strEQ(d,"getc"))
  966.         FOP(O_GETC);
  967.     if (strnEQ(d,"get",3)) {
  968.         d += 3;
  969.         if (*d == 'p') {
  970.         if (strEQ(d,"ppid"))
  971.             FUN0(O_GETPPID);
  972.         if (strEQ(d,"pgrp"))
  973.             UNI(O_GETPGRP);
  974.         if (strEQ(d,"priority"))
  975.             FUN2(O_GETPRIORITY);
  976.         if (strEQ(d,"protobyname"))
  977.             UNI(O_GPBYNAME);
  978.         if (strEQ(d,"protobynumber"))
  979.             FUN1(O_GPBYNUMBER);
  980.         if (strEQ(d,"protoent"))
  981.             FUN0(O_GPROTOENT);
  982.         if (strEQ(d,"pwent"))
  983.             FUN0(O_GPWENT);
  984.         if (strEQ(d,"pwnam"))
  985.             FUN1(O_GPWNAM);
  986.         if (strEQ(d,"pwuid"))
  987.             FUN1(O_GPWUID);
  988.         if (strEQ(d,"peername"))
  989.             FOP(O_GETPEERNAME);
  990.         }
  991.         else if (*d == 'h') {
  992.         if (strEQ(d,"hostbyname"))
  993.             UNI(O_GHBYNAME);
  994.         if (strEQ(d,"hostbyaddr"))
  995.             FUN2(O_GHBYADDR);
  996.         if (strEQ(d,"hostent"))
  997.             FUN0(O_GHOSTENT);
  998.         }
  999.         else if (*d == 'n') {
  1000.         if (strEQ(d,"netbyname"))
  1001.             UNI(O_GNBYNAME);
  1002.         if (strEQ(d,"netbyaddr"))
  1003.             FUN2(O_GNBYADDR);
  1004.         if (strEQ(d,"netent"))
  1005.             FUN0(O_GNETENT);
  1006.         }
  1007.         else if (*d == 's') {
  1008.         if (strEQ(d,"servbyname"))
  1009.             FUN2(O_GSBYNAME);
  1010.         if (strEQ(d,"servbyport"))
  1011.             FUN2(O_GSBYPORT);
  1012.         if (strEQ(d,"servent"))
  1013.             FUN0(O_GSERVENT);
  1014.         if (strEQ(d,"sockname"))
  1015.             FOP(O_GETSOCKNAME);
  1016.         if (strEQ(d,"sockopt"))
  1017.             FOP3(O_GSOCKOPT);
  1018.         }
  1019.         else if (*d == 'g') {
  1020.         if (strEQ(d,"grent"))
  1021.             FUN0(O_GGRENT);
  1022.         if (strEQ(d,"grnam"))
  1023.             FUN1(O_GGRNAM);
  1024.         if (strEQ(d,"grgid"))
  1025.             FUN1(O_GGRGID);
  1026.         }
  1027.         else if (*d == 'l') {
  1028.         if (strEQ(d,"login"))
  1029.             FUN0(O_GETLOGIN);
  1030.         }
  1031.         d -= 3;
  1032.     }
  1033.     break;
  1034.     case 'h': case 'H':
  1035.     SNARFWORD;
  1036.     if (strEQ(d,"hex"))
  1037.         UNI(O_HEX);
  1038.     break;
  1039.     case 'i': case 'I':
  1040.     SNARFWORD;
  1041.     if (strEQ(d,"if")) {
  1042.         yylval.ival = curcmd->c_line;
  1043.         OPERATOR(IF);
  1044.     }
  1045.     if (strEQ(d,"index"))
  1046.         FUN2x(O_INDEX);
  1047.     if (strEQ(d,"int"))
  1048.         UNI(O_INT);
  1049.     if (strEQ(d,"ioctl"))
  1050.         FOP3(O_IOCTL);
  1051.     break;
  1052.     case 'j': case 'J':
  1053.     SNARFWORD;
  1054.     if (strEQ(d,"join"))
  1055.         FL2(O_JOIN);
  1056.     break;
  1057.     case 'k': case 'K':
  1058.     SNARFWORD;
  1059.     if (strEQ(d,"keys"))
  1060.         HFUN(O_KEYS);
  1061.     if (strEQ(d,"kill"))
  1062.         LOP(O_KILL);
  1063.     break;
  1064.     case 'l': case 'L':
  1065.     SNARFWORD;
  1066.     if (strEQ(d,"last"))
  1067.         LOOPX(O_LAST);
  1068.     if (strEQ(d,"local"))
  1069.         OPERATOR(LOCAL);
  1070.     if (strEQ(d,"length"))
  1071.         UNI(O_LENGTH);
  1072.     if (strEQ(d,"lt") || strEQ(d,"LT"))
  1073.         ROP(O_SLT);
  1074.     if (strEQ(d,"le") || strEQ(d,"LE"))
  1075.         ROP(O_SLE);
  1076.     if (strEQ(d,"localtime"))
  1077.         UNI(O_LOCALTIME);
  1078.     if (strEQ(d,"log"))
  1079.         UNI(O_LOG);
  1080.     if (strEQ(d,"link"))
  1081.         FUN2(O_LINK);
  1082.     if (strEQ(d,"listen"))
  1083.         FOP2(O_LISTEN);
  1084.     if (strEQ(d,"lstat"))
  1085.         FOP(O_LSTAT);
  1086.     break;
  1087.     case 'm': case 'M':
  1088.     if (s[1] == '\'') {
  1089.         d = "m";
  1090.         s++;
  1091.     }
  1092.     else {
  1093.         SNARFWORD;
  1094.     }
  1095.     if (strEQ(d,"m")) {
  1096.         s = scanpat(s-1);
  1097.         if (yylval.arg)
  1098.         TERM(PATTERN);
  1099.         else
  1100.         RETURN(1);    /* force error */
  1101.     }
  1102.     switch (d[1]) {
  1103.     case 'k':
  1104.         if (strEQ(d,"mkdir"))
  1105.         FUN2(O_MKDIR);
  1106.         break;
  1107.     case 's':
  1108.         if (strEQ(d,"msgctl"))
  1109.         FUN3(O_MSGCTL);
  1110.         if (strEQ(d,"msgget"))
  1111.         FUN2(O_MSGGET);
  1112.         if (strEQ(d,"msgrcv"))
  1113.         FUN5(O_MSGRCV);
  1114.         if (strEQ(d,"msgsnd"))
  1115.         FUN3(O_MSGSND);
  1116.         break;
  1117.     }
  1118.     break;
  1119.     case 'n': case 'N':
  1120.     SNARFWORD;
  1121.     if (strEQ(d,"next"))
  1122.         LOOPX(O_NEXT);
  1123.     if (strEQ(d,"ne") || strEQ(d,"NE"))
  1124.         EOP(O_SNE);
  1125.     break;
  1126.     case 'o': case 'O':
  1127.     SNARFWORD;
  1128.     if (strEQ(d,"open"))
  1129.         OPERATOR(OPEN);
  1130.     if (strEQ(d,"ord"))
  1131.         UNI(O_ORD);
  1132.     if (strEQ(d,"oct"))
  1133.         UNI(O_OCT);
  1134.     if (strEQ(d,"opendir"))
  1135.         FOP2(O_OPEN_DIR);
  1136.     break;
  1137.     case 'p': case 'P':
  1138.     SNARFWORD;
  1139.     if (strEQ(d,"print")) {
  1140.         checkcomma(s,d,"filehandle");
  1141.         LOP(O_PRINT);
  1142.     }
  1143.     if (strEQ(d,"printf")) {
  1144.         checkcomma(s,d,"filehandle");
  1145.         LOP(O_PRTF);
  1146.     }
  1147.     if (strEQ(d,"push")) {
  1148.         yylval.ival = O_PUSH;
  1149.         OPERATOR(PUSH);
  1150.     }
  1151.     if (strEQ(d,"pop"))
  1152.         OPERATOR(POP);
  1153.     if (strEQ(d,"pack"))
  1154.         FL2(O_PACK);
  1155.     if (strEQ(d,"package"))
  1156.         OPERATOR(PACKAGE);
  1157. #ifdef macintosh
  1158.     if (strEQ(d,"pick"))
  1159.         MIN1(O_PICK);
  1160. #endif
  1161.     if (strEQ(d,"pipe"))
  1162.         FOP22(O_PIPE_OP);
  1163.     break;
  1164.     case 'q': case 'Q':
  1165.     SNARFWORD;
  1166.     if (strEQ(d,"q")) {
  1167.         s = scanstr(s-1, SCAN_DEF);
  1168.         TERM(RSTRING);
  1169.     }
  1170.     if (strEQ(d,"qq")) {
  1171.         s = scanstr(s-2, SCAN_DEF);
  1172.         TERM(RSTRING);
  1173.     }
  1174.     if (strEQ(d,"qx")) {
  1175.         s = scanstr(s-2, SCAN_DEF);
  1176.         TERM(RSTRING);
  1177.     }
  1178.     break;
  1179.     case 'r': case 'R':
  1180.     SNARFWORD;
  1181.     if (strEQ(d,"return"))
  1182.         OLDLOP(O_RETURN);
  1183.     if (strEQ(d,"require")) {
  1184.         allstabs = TRUE;        /* must initialize everything since */
  1185.         UNI(O_REQUIRE);        /* we don't know what will be used */
  1186.     }
  1187.     if (strEQ(d,"reset"))
  1188.         UNI(O_RESET);
  1189.     if (strEQ(d,"redo"))
  1190.         LOOPX(O_REDO);
  1191.     if (strEQ(d,"rename"))
  1192.         FUN2(O_RENAME);
  1193.     if (strEQ(d,"rand"))
  1194.         UNI(O_RAND);
  1195.     if (strEQ(d,"rmdir"))
  1196.         UNI(O_RMDIR);
  1197.     if (strEQ(d,"rindex"))
  1198.         FUN2x(O_RINDEX);
  1199.     if (strEQ(d,"read"))
  1200.         FOP3(O_READ);
  1201.     if (strEQ(d,"readdir"))
  1202.         FOP(O_READDIR);
  1203.     if (strEQ(d,"rewinddir"))
  1204.         FOP(O_REWINDDIR);
  1205.     if (strEQ(d,"recv"))
  1206.         FOP4(O_RECV);
  1207.     if (strEQ(d,"reverse"))
  1208.         LOP(O_REVERSE);
  1209.     if (strEQ(d,"readlink"))
  1210.         UNI(O_READLINK);
  1211.     break;
  1212.     case 's': case 'S':
  1213.     if (s[1] == '\'') {
  1214.         d = "s";
  1215.         s++;
  1216.     }
  1217.     else {
  1218.         SNARFWORD;
  1219.     }
  1220.     if (strEQ(d,"s")) {
  1221.         s = scansubst(s);
  1222.         if (yylval.arg)
  1223.         TERM(SUBST);
  1224.         else
  1225.         RETURN(1);    /* force error */
  1226.     }
  1227.     switch (d[1]) {
  1228.     case 'a':
  1229.     case 'b':
  1230.         break;
  1231.     case 'c':
  1232.         if (strEQ(d,"scalar"))
  1233.         UNI(O_SCALAR);
  1234.         break;
  1235.     case 'd':
  1236.         break;
  1237.     case 'e':
  1238.         if (strEQ(d,"select"))
  1239.         OPERATOR(SSELECT);
  1240.         if (strEQ(d,"seek"))
  1241.         FOP3(O_SEEK);
  1242.         if (strEQ(d,"semctl"))
  1243.         FUN4(O_SEMCTL);
  1244.         if (strEQ(d,"semget"))
  1245.         FUN3(O_SEMGET);
  1246.         if (strEQ(d,"semop"))
  1247.         FUN2(O_SEMOP);
  1248.         if (strEQ(d,"send"))
  1249.         FOP3(O_SEND);
  1250.         if (strEQ(d,"setpgrp"))
  1251.         FUN2(O_SETPGRP);
  1252.         if (strEQ(d,"setpriority"))
  1253.         FUN3(O_SETPRIORITY);
  1254.         if (strEQ(d,"sethostent"))
  1255.         FUN1(O_SHOSTENT);
  1256.         if (strEQ(d,"setnetent"))
  1257.         FUN1(O_SNETENT);
  1258.         if (strEQ(d,"setservent"))
  1259.         FUN1(O_SSERVENT);
  1260.         if (strEQ(d,"setprotoent"))
  1261.         FUN1(O_SPROTOENT);
  1262.         if (strEQ(d,"setpwent"))
  1263.         FUN0(O_SPWENT);
  1264.         if (strEQ(d,"setgrent"))
  1265.         FUN0(O_SGRENT);
  1266.         if (strEQ(d,"seekdir"))
  1267.         FOP2(O_SEEKDIR);
  1268.         if (strEQ(d,"setsockopt"))
  1269.         FOP4(O_SSOCKOPT);
  1270.         break;
  1271.     case 'f':
  1272.     case 'g':
  1273.         break;
  1274.     case 'h':
  1275.         if (strEQ(d,"shift"))
  1276.         TERM(SHIFT);
  1277.         if (strEQ(d,"shmctl"))
  1278.         FUN3(O_SHMCTL);
  1279.         if (strEQ(d,"shmget"))
  1280.         FUN3(O_SHMGET);
  1281.         if (strEQ(d,"shmread"))
  1282.         FUN4(O_SHMREAD);
  1283.         if (strEQ(d,"shmwrite"))
  1284.         FUN4(O_SHMWRITE);
  1285.         if (strEQ(d,"shutdown"))
  1286.         FOP2(O_SHUTDOWN);
  1287.         break;
  1288.     case 'i':
  1289.         if (strEQ(d,"sin"))
  1290.         UNI(O_SIN);
  1291.         break;
  1292.     case 'j':
  1293.     case 'k':
  1294.         break;
  1295.     case 'l':
  1296.         if (strEQ(d,"sleep"))
  1297.         UNI(O_SLEEP);
  1298.         break;
  1299.     case 'm':
  1300.     case 'n':
  1301.         break;
  1302.     case 'o':
  1303.         if (strEQ(d,"socket"))
  1304.         FOP4(O_SOCKET);
  1305.         if (strEQ(d,"socketpair"))
  1306.         FOP25(O_SOCKPAIR);
  1307.         if (strEQ(d,"sort")) {
  1308.         checkcomma(s,d,"subroutine name");
  1309.         d = bufend;
  1310.         while (s < d && isSPACE(*s)) s++;
  1311.         if (*s == ';' || *s == ')')        /* probably a close */
  1312.             fatal("sort is now a reserved word");
  1313.         if (isALPHA(*s) || *s == '_') {
  1314.             /*SUPPRESS 530*/
  1315.             for (d = s; isALNUM(*d); d++) ;
  1316.             strncpy(tokenbuf,s,d-s);
  1317.             tokenbuf[d-s] = '\0';
  1318.             if (strNE(tokenbuf,"keys") &&
  1319.             strNE(tokenbuf,"values") &&
  1320.             strNE(tokenbuf,"split") &&
  1321.             strNE(tokenbuf,"grep") &&
  1322.             strNE(tokenbuf,"readdir") &&
  1323.             strNE(tokenbuf,"unpack") &&
  1324.             strNE(tokenbuf,"do") &&
  1325.             strNE(tokenbuf,"eval") &&
  1326.             (d >= bufend || isSPACE(*d)) )
  1327.             *(--s) = '\\';    /* force next ident to WORD */
  1328.         }
  1329.         LOP(O_SORT);
  1330.         }
  1331.         break;
  1332.     case 'p':
  1333.         if (strEQ(d,"split"))
  1334.         TERM(SPLIT);
  1335.         if (strEQ(d,"sprintf"))
  1336.         FL(O_SPRINTF);
  1337.         if (strEQ(d,"splice")) {
  1338.         yylval.ival = O_SPLICE;
  1339.         OPERATOR(PUSH);
  1340.         }
  1341.         break;
  1342.     case 'q':
  1343.         if (strEQ(d,"sqrt"))
  1344.         UNI(O_SQRT);
  1345.         break;
  1346.     case 'r':
  1347.         if (strEQ(d,"srand"))
  1348.         UNI(O_SRAND);
  1349.         break;
  1350.     case 's':
  1351.         break;
  1352.     case 't':
  1353.         if (strEQ(d,"stat"))
  1354.         FOP(O_STAT);
  1355.         if (strEQ(d,"study")) {
  1356.         sawstudy++;
  1357.         LFUN(O_STUDY);
  1358.         }
  1359.         break;
  1360.     case 'u':
  1361.         if (strEQ(d,"substr"))
  1362.         FUN2x(O_SUBSTR);
  1363.         if (strEQ(d,"sub")) {
  1364.         yylval.ival = savestack->ary_fill; /* restore stuff on reduce */
  1365.         savelong(&subline);
  1366.         saveitem(subname);
  1367.  
  1368.         subline = curcmd->c_line;
  1369.         d = bufend;
  1370.         while (s < d && isSPACE(*s))
  1371.             s++;
  1372.         if (isALPHA(*s) || *s == '_' || *s == '\'') {
  1373.             str_sset(subname,curstname);
  1374.             str_ncat(subname,"'",1);
  1375.             for (d = s+1; isALNUM(*d) || *d == '\''; d++)
  1376.             /*SUPPRESS 530*/
  1377.             ;
  1378.             if (d[-1] == '\'')
  1379.             d--;
  1380.             str_ncat(subname,s,d-s);
  1381.             *(--s) = '\\';    /* force next ident to WORD */
  1382.         }
  1383.         else
  1384.             str_set(subname,"?");
  1385.         OPERATOR(SUB);
  1386.         }
  1387.         break;
  1388.     case 'v':
  1389.     case 'w':
  1390.     case 'x':
  1391.         break;
  1392.     case 'y':
  1393.         if (strEQ(d,"system")) {
  1394.         set_csh();
  1395.         LOP(O_SYSTEM);
  1396.         }
  1397.         if (strEQ(d,"symlink"))
  1398.         FUN2(O_SYMLINK);
  1399.         if (strEQ(d,"syscall"))
  1400.         LOP(O_SYSCALL);
  1401.         if (strEQ(d,"sysread"))
  1402.         FOP3(O_SYSREAD);
  1403.         if (strEQ(d,"syswrite"))
  1404.         FOP3(O_SYSWRITE);
  1405.         break;
  1406.     case 'z':
  1407.         break;
  1408.     }
  1409.     break;
  1410.     case 't': case 'T':
  1411.     SNARFWORD;
  1412.     if (strEQ(d,"tr")) {
  1413.         s = scantrans(s);
  1414.         if (yylval.arg)
  1415.         TERM(TRANS);
  1416.         else
  1417.         RETURN(1);    /* force error */
  1418.     }
  1419.     if (strEQ(d,"tell"))
  1420.         FOP(O_TELL);
  1421.     if (strEQ(d,"telldir"))
  1422.         FOP(O_TELLDIR);
  1423.     if (strEQ(d,"time"))
  1424.         FUN0(O_TIME);
  1425.     if (strEQ(d,"times"))
  1426.         FUN0(O_TMS);
  1427.     if (strEQ(d,"truncate"))
  1428.         FOP2(O_TRUNCATE);
  1429.     break;
  1430.     case 'u': case 'U':
  1431.     SNARFWORD;
  1432.     if (strEQ(d,"using"))
  1433.         OPERATOR(USING);
  1434.     if (strEQ(d,"until")) {
  1435.         yylval.ival = curcmd->c_line;
  1436.         OPERATOR(UNTIL);
  1437.     }
  1438.     if (strEQ(d,"unless")) {
  1439.         yylval.ival = curcmd->c_line;
  1440.         OPERATOR(UNLESS);
  1441.     }
  1442.     if (strEQ(d,"unlink"))
  1443.         LOP(O_UNLINK);
  1444.     if (strEQ(d,"undef"))
  1445.         LFUN(O_UNDEF);
  1446.     if (strEQ(d,"unpack"))
  1447.         FUN2(O_UNPACK);
  1448.     if (strEQ(d,"utime"))
  1449.         LOP(O_UTIME);
  1450.     if (strEQ(d,"umask"))
  1451.         UNI(O_UMASK);
  1452.     if (strEQ(d,"unshift")) {
  1453.         yylval.ival = O_UNSHIFT;
  1454.         OPERATOR(PUSH);
  1455.     }
  1456.     break;
  1457.     case 'v': case 'V':
  1458.     SNARFWORD;
  1459.     if (strEQ(d,"values"))
  1460.         HFUN(O_VALUES);
  1461.     if (strEQ(d,"vec")) {
  1462.         sawvec = TRUE;
  1463.         FUN3(O_VEC);
  1464.     }
  1465.     break;
  1466.     case 'w': case 'W':
  1467.     SNARFWORD;
  1468.     if (strEQ(d,"while")) {
  1469.         yylval.ival = curcmd->c_line;
  1470.         OPERATOR(WHILE);
  1471.     }
  1472.     if (strEQ(d,"warn"))
  1473.         LOP(O_WARN);
  1474.     if (strEQ(d,"wait"))
  1475.         FUN0(O_WAIT);
  1476.     if (strEQ(d,"waitpid"))
  1477.         FUN2(O_WAITPID);
  1478.     if (strEQ(d,"wantarray")) {
  1479.         yylval.arg = op_new(1);
  1480.         yylval.arg->arg_type = O_ITEM;
  1481.         yylval.arg[1].arg_type = A_WANTARRAY;
  1482.         TERM(RSTRING);
  1483.     }
  1484.     if (strEQ(d,"write"))
  1485.         FOP(O_WRITE);
  1486.     break;
  1487.     case 'x': case 'X':
  1488.     if (*s == 'x' && isDIGIT(s[1]) && !expectterm) {
  1489.         s++;
  1490.         MOP(O_REPEAT);
  1491.     }
  1492.     SNARFWORD;
  1493.     if (strEQ(d,"x")) {
  1494.         if (!expectterm)
  1495.         MOP(O_REPEAT);
  1496.         check_uni();
  1497.     }
  1498.     break;
  1499.     case 'y': case 'Y':
  1500.     if (s[1] == '\'') {
  1501.         d = "y";
  1502.         s++;
  1503.     }
  1504.     else {
  1505.         SNARFWORD;
  1506.     }
  1507.     if (strEQ(d,"y")) {
  1508.         s = scantrans(s);
  1509.         TERM(TRANS);
  1510.     }
  1511.     break;
  1512.     case 'z': case 'Z':
  1513.     SNARFWORD;
  1514.     break;
  1515.     }
  1516.     yylval.cval = savestr(d);
  1517.     if (expectterm == 2) {        /* special case: start of statement */
  1518.     while (isSPACE(*s)) s++;
  1519.     if (*s == ':') {
  1520.         s++;
  1521.         CLINE;
  1522.         OPERATOR(LABEL);
  1523.     }
  1524.     TERM(WORD);
  1525.     }
  1526.     expectterm = FALSE;
  1527.     if (oldoldbufptr && oldoldbufptr < bufptr) {
  1528.     while (isSPACE(*oldoldbufptr))
  1529.         oldoldbufptr++;
  1530.     if (*oldoldbufptr == 'p' && strnEQ(oldoldbufptr,"print",5))
  1531.         expectterm = TRUE;
  1532.     else if (*oldoldbufptr == 's' && strnEQ(oldoldbufptr,"sort",4))
  1533.         expectterm = TRUE;
  1534.     }
  1535.     return (CLINE, bufptr = s, (int)WORD);
  1536. }
  1537.  
  1538. void
  1539. checkcomma(s,name,what)
  1540. register char *s;
  1541. char *name;
  1542. char *what;
  1543. {
  1544.     char *w;
  1545.  
  1546.     if (dowarn && *s == ' ' && s[1] == '(') {
  1547.     w = index(s,')');
  1548.     if (w)
  1549.         for (w++; *w && isSPACE(*w); w++) ;
  1550.     if (!w || !*w || !index(";|}", *w))    /* an advisory hack only... */
  1551.         warn("%s (...) interpreted as function",name);
  1552.     }
  1553.     while (s < bufend && isSPACE(*s))
  1554.     s++;
  1555.     if (*s == '(')
  1556.     s++;
  1557.     while (s < bufend && isSPACE(*s))
  1558.     s++;
  1559.     if (isALPHA(*s) || *s == '_') {
  1560.     w = s++;
  1561.     while (isALNUM(*s))
  1562.         s++;
  1563.     while (s < bufend && isSPACE(*s))
  1564.         s++;
  1565.     if (*s == ',') {
  1566.         *s = '\0';
  1567.         w = instr(
  1568.           "tell eof times getlogin wait length shift umask getppid \
  1569.           cos exp int log rand sin sqrt ord wantarray",
  1570.           w);
  1571.         *s = ',';
  1572.         if (w)
  1573.         return;
  1574.         fatal("No comma allowed after %s", what);
  1575.     }
  1576.     }
  1577. }
  1578.  
  1579. char *
  1580. scanident(s,send,dest)
  1581. register char *s;
  1582. register char *send;
  1583. char *dest;
  1584. {
  1585.     register char *d;
  1586.     int brackets = 0;
  1587.  
  1588.     reparse = Nullch;
  1589.     s++;
  1590.     d = dest;
  1591.     if (isDIGIT(*s)) {
  1592.     while (isDIGIT(*s))
  1593.         *d++ = *s++;
  1594.     }
  1595.     else {
  1596.     while (isALNUM(*s) || *s == '\'')
  1597.         *d++ = *s++;
  1598.     }
  1599.     while (d > dest+1 && d[-1] == '\'')
  1600.     d--,s--;
  1601.     *d = '\0';
  1602.     d = dest;
  1603.     if (!*d) {
  1604.     *d = *s++;
  1605.     if (*d == '{' /* } */ ) {
  1606.         d = dest;
  1607.         brackets++;
  1608.         while (s < send && brackets) {
  1609.         if (!reparse && (d == dest || (*s && isALNUM(*s) ))) {
  1610.             *d++ = *s++;
  1611.             continue;
  1612.         }
  1613.         else if (!reparse)
  1614.             reparse = s;
  1615.         switch (*s++) {
  1616.         /* { */
  1617.         case '}':
  1618.             brackets--;
  1619.             if (reparse && reparse == s - 1)
  1620.             reparse = Nullch;
  1621.             break;
  1622.         case '{':   /* } */
  1623.             brackets++;
  1624.             break;
  1625.         }
  1626.         }
  1627.         *d = '\0';
  1628.         d = dest;
  1629.     }
  1630.     else
  1631.         d[1] = '\0';
  1632.     }
  1633.     if (*d == '^' && (isUPPER(*s) || index("[\\]^_?", *s))) {
  1634. #ifdef DEBUGGING
  1635.     if (*s == 'D')
  1636.         debug |= 32768;
  1637. #endif
  1638.     *d = *s++ ^ 64;
  1639.     }
  1640.     return s;
  1641. }
  1642.  
  1643. void
  1644. scanconst(spat,string,len)
  1645. SPAT *spat;
  1646. char *string;
  1647. int len;
  1648. {
  1649.     register STR *tmpstr;
  1650.     register char *t;
  1651.     register char *d;
  1652.     register char *e;
  1653.     char *origstring = string;
  1654.     static char *vert = "|";
  1655.  
  1656.     if (ninstr(string, string+len, vert, vert+1))
  1657.     return;
  1658.     if (*string == '^')
  1659.     string++, len--;
  1660.     tmpstr = Str_new(86,len);
  1661.     str_nset(tmpstr,string,len);
  1662.     t = str_get(tmpstr);
  1663.     e = t + len;
  1664.     tmpstr->str_u.str_useful = 100;
  1665.     for (d=t; d < e; ) {
  1666.     switch (*d) {
  1667.     case '{':
  1668.         if (isDIGIT(d[1]))
  1669.         e = d;
  1670.         else
  1671.         goto defchar;
  1672.         break;
  1673.     case '.': case '[': case '$': case '(': case ')': case '|': case '+':
  1674.     case '^':
  1675.         e = d;
  1676.         break;
  1677.     case '\\':
  1678.         if (d[1] && index("wWbB0123456789sSdDlLuUExc",d[1])) {
  1679.         e = d;
  1680.         break;
  1681.         }
  1682.         Move(d+1,d,e-d,char);
  1683.         e--;
  1684.         switch(*d) {
  1685.         case 'n':
  1686.         *d = '\n';
  1687.         break;
  1688.         case 't':
  1689.         *d = '\t';
  1690.         break;
  1691.         case 'f':
  1692.         *d = '\f';
  1693.         break;
  1694.         case 'r':
  1695.         *d = '\r';
  1696.         break;
  1697.         case 'e':
  1698.         *d = '\033';
  1699.         break;
  1700.         case 'a':
  1701.         *d = '\007';
  1702.         break;
  1703.         }
  1704.         /* FALL THROUGH */
  1705.     default:
  1706.       defchar:
  1707.         if (d[1] == '*' || (d[1] == '{' && d[2] == '0') || d[1] == '?') {
  1708.         e = d;
  1709.         break;
  1710.         }
  1711.         d++;
  1712.     }
  1713.     }
  1714.     if (d == t) {
  1715.     str_free(tmpstr);
  1716.     return;
  1717.     }
  1718.     *d = '\0';
  1719.     tmpstr->str_cur = d - t;
  1720.     if (d == t+len)
  1721.     spat->spat_flags |= SPAT_ALL;
  1722.     if (*origstring != '^')
  1723.     spat->spat_flags |= SPAT_SCANFIRST;
  1724.     spat->spat_short = tmpstr;
  1725.     spat->spat_slen = d - t;
  1726. }
  1727.  
  1728. char *
  1729. scanpat(s)
  1730. register char *s;
  1731. {
  1732.     register SPAT *spat;
  1733.     register char *d;
  1734.     register char *e;
  1735.     int len;
  1736.     SPAT savespat;
  1737.     STR *str = Str_new(93,0);
  1738.     char delim;
  1739.  
  1740.     Newz(801,spat,1,SPAT);
  1741.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1742.     curstash->tbl_spatroot = spat;
  1743.  
  1744.     switch (*s++) {
  1745.     case 'm':
  1746.     s++;
  1747.     break;
  1748.     case '/':
  1749.     break;
  1750.     case '?':
  1751.     spat->spat_flags |= SPAT_ONCE;
  1752.     break;
  1753.     default:
  1754.     fatal("panic: scanpat");
  1755.     }
  1756.     s = str_append_till(str,s,bufend,s[-1],patleave);
  1757.     if (s >= bufend) {
  1758.     str_free(str);
  1759.     yyerror("Search pattern not terminated");
  1760.     yylval.arg = Nullarg;
  1761.     return s;
  1762.     }
  1763.     delim = *s++;
  1764.     while (*s == 'i' || *s == 'o' || *s == 'g') {
  1765.     if (*s == 'i') {
  1766.         s++;
  1767.         sawi = TRUE;
  1768.         spat->spat_flags |= SPAT_FOLD;
  1769.     }
  1770.     if (*s == 'o') {
  1771.         s++;
  1772.         spat->spat_flags |= SPAT_KEEP;
  1773.     }
  1774.     if (*s == 'g') {
  1775.         s++;
  1776.         spat->spat_flags |= SPAT_GLOBAL;
  1777.     }
  1778.     }
  1779.     len = str->str_cur;
  1780.     e = str->str_ptr + len;
  1781.     if (delim == '\'')
  1782.     d = e;
  1783.     else
  1784.     d = str->str_ptr;
  1785.     for (; d < e; d++) {
  1786.     if (*d == '\\')
  1787.         d++;
  1788.     else if ((*d == '$' && d[1] && d[1] != '|' && d[1] != ')') ||
  1789.          (*d == '@')) {
  1790.         register ARG *arg;
  1791.  
  1792.         spat->spat_runtime = arg = op_new(1);
  1793.         arg->arg_type = O_ITEM;
  1794.         arg[1].arg_type = A_DOUBLE;
  1795.         arg[1].arg_ptr.arg_str = str_smake(str);
  1796.         d = scanident(d,bufend,buf);
  1797.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1798.         for (; d < e; d++) {
  1799.         if (*d == '\\')
  1800.             d++;
  1801.         else if (*d == '$' && d[1] && d[1] != '|' && d[1] != ')') {
  1802.             d = scanident(d,bufend,buf);
  1803.             (void)stabent(buf,TRUE);
  1804.         }
  1805.         else if (*d == '@') {
  1806.             d = scanident(d,bufend,buf);
  1807.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1808.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1809.             (void)stabent(buf,TRUE);
  1810.         }
  1811.         }
  1812.         goto got_pat;        /* skip compiling for now */
  1813.     }
  1814.     }
  1815.     if (spat->spat_flags & SPAT_FOLD)
  1816.     StructCopy(spat, &savespat, SPAT);
  1817.     scanconst(spat,str->str_ptr,len);
  1818.     if ((spat->spat_flags & SPAT_ALL) && (spat->spat_flags & SPAT_SCANFIRST)) {
  1819.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1820.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1821.         spat->spat_flags & SPAT_FOLD);
  1822.         /* Note that this regexp can still be used if someone says
  1823.          * something like /a/ && s//b/;  so we can't delete it.
  1824.          */
  1825.     }
  1826.     else {
  1827.     if (spat->spat_flags & SPAT_FOLD)
  1828.     StructCopy(&savespat, spat, SPAT);
  1829.     if (spat->spat_short)
  1830.         fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1831.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1832.         spat->spat_flags & SPAT_FOLD);
  1833.     hoistmust(spat);
  1834.     }
  1835.   got_pat:
  1836.     str_free(str);
  1837.     yylval.arg = make_match(O_MATCH,stab2arg(A_STAB,defstab),spat);
  1838.     return s;
  1839. }
  1840.  
  1841. char *
  1842. scansubst(start)
  1843. char *start;
  1844. {
  1845.     register char *s = start;
  1846.     register SPAT *spat;
  1847.     register char *d;
  1848.     register char *e;
  1849.     int len;
  1850.     STR *str = Str_new(93,0);
  1851.     char term = *s;
  1852.  
  1853.     if (term && (d = index("([{< )]}> )]}>",term)))
  1854.     term = d[5];
  1855.  
  1856.     Newz(802,spat,1,SPAT);
  1857.     spat->spat_next = curstash->tbl_spatroot;    /* link into spat list */
  1858.     curstash->tbl_spatroot = spat;
  1859.  
  1860.     s = str_append_till(str,s+1,bufend,term,patleave);
  1861.     if (s >= bufend) {
  1862.     str_free(str);
  1863.     yyerror("Substitution pattern not terminated");
  1864.     yylval.arg = Nullarg;
  1865.     return s;
  1866.     }
  1867.     len = str->str_cur;
  1868.     e = str->str_ptr + len;
  1869.     for (d = str->str_ptr; d < e; d++) {
  1870.     if (*d == '\\')
  1871.         d++;
  1872.     else if ((*d == '$' && d[1] && d[1] != '|' && /*(*/ d[1] != ')') ||
  1873.         *d == '@' ) {
  1874.         register ARG *arg;
  1875.  
  1876.         spat->spat_runtime = arg = op_new(1);
  1877.         arg->arg_type = O_ITEM;
  1878.         arg[1].arg_type = A_DOUBLE;
  1879.         arg[1].arg_ptr.arg_str = str_smake(str);
  1880.         d = scanident(d,e,buf);
  1881.         (void)stabent(buf,TRUE);        /* make sure it's created */
  1882.         for (; *d; d++) {
  1883.         if (*d == '$' && d[1] && d[-1] != '\\' && d[1] != '|') {
  1884.             d = scanident(d,e,buf);
  1885.             (void)stabent(buf,TRUE);
  1886.         }
  1887.         else if (*d == '@' && d[-1] != '\\') {
  1888.             d = scanident(d,e,buf);
  1889.             if (strEQ(buf,"ARGV") || strEQ(buf,"ENV") ||
  1890.               strEQ(buf,"SIG") || strEQ(buf,"INC"))
  1891.             (void)stabent(buf,TRUE);
  1892.         }
  1893.         }
  1894.         goto get_repl;        /* skip compiling for now */
  1895.     }
  1896.     }
  1897.     scanconst(spat,str->str_ptr,len);
  1898. get_repl:
  1899.     if (term != *start)
  1900.     s++;
  1901.     s = scanstr(s, SCAN_REPL);
  1902.     if (s >= bufend) {
  1903.     str_free(str);
  1904.     yyerror("Substitution replacement not terminated");
  1905.     yylval.arg = Nullarg;
  1906.     return s;
  1907.     }
  1908.     spat->spat_repl = yylval.arg;
  1909.     if ((spat->spat_repl[1].arg_type & A_MASK) == A_SINGLE)
  1910.     spat->spat_flags |= SPAT_CONST;
  1911.     else if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE) {
  1912.     STR *tmpstr;
  1913.     register char *t;
  1914.  
  1915.     spat->spat_flags |= SPAT_CONST;
  1916.     tmpstr = spat->spat_repl[1].arg_ptr.arg_str;
  1917.     e = tmpstr->str_ptr + tmpstr->str_cur;
  1918.     for (t = tmpstr->str_ptr; t < e; t++) {
  1919.         if (*t == '$' && t[1] && (index("`'&+0123456789",t[1]) ||
  1920.           (t[1] == '{' /*}*/ && isDIGIT(t[2])) ))
  1921.         spat->spat_flags &= ~SPAT_CONST;
  1922.     }
  1923.     }
  1924.     while (*s == 'g' || *s == 'i' || *s == 'e' || *s == 'o') {
  1925.     int es = 0;
  1926.  
  1927.     if (*s == 'e') {
  1928.         s++;
  1929.         es++;
  1930.         if ((spat->spat_repl[1].arg_type & A_MASK) == A_DOUBLE)
  1931.         spat->spat_repl[1].arg_type = A_SINGLE;
  1932.         spat->spat_repl = make_op(
  1933.         (!es && spat->spat_repl[1].arg_type == A_SINGLE
  1934.             ? O_EVALONCE
  1935.             : O_EVAL),
  1936.         2,
  1937.         spat->spat_repl,
  1938.         Nullarg,
  1939.         Nullarg);
  1940.         spat->spat_flags &= ~SPAT_CONST;
  1941.     }
  1942.     if (*s == 'g') {
  1943.         s++;
  1944.         spat->spat_flags |= SPAT_GLOBAL;
  1945.     }
  1946.     if (*s == 'i') {
  1947.         s++;
  1948.         sawi = TRUE;
  1949.         spat->spat_flags |= SPAT_FOLD;
  1950.         if (!(spat->spat_flags & SPAT_SCANFIRST)) {
  1951.         str_free(spat->spat_short);    /* anchored opt doesn't do */
  1952.         spat->spat_short = Nullstr;    /* case insensitive match */
  1953.         spat->spat_slen = 0;
  1954.         }
  1955.     }
  1956.     if (*s == 'o') {
  1957.         s++;
  1958.         spat->spat_flags |= SPAT_KEEP;
  1959.     }
  1960.     }
  1961.     if (spat->spat_short && (spat->spat_flags & SPAT_SCANFIRST))
  1962.     fbmcompile(spat->spat_short, spat->spat_flags & SPAT_FOLD);
  1963.     if (!spat->spat_runtime) {
  1964.     spat->spat_regexp = regcomp(str->str_ptr,str->str_ptr+len,
  1965.       spat->spat_flags & SPAT_FOLD);
  1966.     hoistmust(spat);
  1967.     }
  1968.     yylval.arg = make_match(O_SUBST,stab2arg(A_STAB,defstab),spat);
  1969.     str_free(str);
  1970.     return s;
  1971. }
  1972.  
  1973. void
  1974. hoistmust(spat)
  1975. register SPAT *spat;
  1976. {
  1977.     if (!spat->spat_short && spat->spat_regexp->regstart &&
  1978.     (!spat->spat_regexp->regmust || spat->spat_regexp->reganch & ROPT_ANCH)
  1979.        ) {
  1980.     if (!(spat->spat_regexp->reganch & ROPT_ANCH))
  1981.         spat->spat_flags |= SPAT_SCANFIRST;
  1982.     else if (spat->spat_flags & SPAT_FOLD)
  1983.         return;
  1984.     spat->spat_short = str_smake(spat->spat_regexp->regstart);
  1985.     }
  1986.     else if (spat->spat_regexp->regmust) {/* is there a better short-circuit? */
  1987.     if (spat->spat_short &&
  1988.       str_eq(spat->spat_short,spat->spat_regexp->regmust))
  1989.     {
  1990.         if (spat->spat_flags & SPAT_SCANFIRST) {
  1991.         str_free(spat->spat_short);
  1992.         spat->spat_short = Nullstr;
  1993.         }
  1994.         else {
  1995.         str_free(spat->spat_regexp->regmust);
  1996.         spat->spat_regexp->regmust = Nullstr;
  1997.         return;
  1998.         }
  1999.     }
  2000.     if (!spat->spat_short ||    /* promote the better string */
  2001.       ((spat->spat_flags & SPAT_SCANFIRST) &&
  2002.        (spat->spat_short->str_cur < spat->spat_regexp->regmust->str_cur) )){
  2003.         str_free(spat->spat_short);        /* ok if null */
  2004.         spat->spat_short = spat->spat_regexp->regmust;
  2005.         spat->spat_regexp->regmust = Nullstr;
  2006.         spat->spat_flags |= SPAT_SCANFIRST;
  2007.     }
  2008.     }
  2009. }
  2010.  
  2011. char *
  2012. scantrans(start)
  2013. char *start;
  2014. {
  2015.     register char *s = start;
  2016.     ARG *arg =
  2017.     l(make_op(O_TRANS,2,stab2arg(A_STAB,defstab),Nullarg,Nullarg));
  2018.     STR *tstr;
  2019.     STR *rstr;
  2020.     register char *t;
  2021.     register char *r;
  2022.     register short *tbl;
  2023.     register int i;
  2024.     register int j;
  2025.     int tlen, rlen;
  2026.     int squash;
  2027.     int delete;
  2028.     int complement;
  2029.  
  2030.     New(803,tbl,256,short);
  2031.     arg[2].arg_type = A_NULL;
  2032.     arg[2].arg_ptr.arg_cval = (char*) tbl;
  2033.  
  2034.     s = scanstr(s, SCAN_TR);
  2035.     if (s >= bufend) {
  2036.     yyerror("Translation pattern not terminated");
  2037.     yylval.arg = Nullarg;
  2038.     return s;
  2039.     }
  2040.     tstr = yylval.arg[1].arg_ptr.arg_str; 
  2041.     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  2042.     arg_free(yylval.arg);
  2043.     t = tstr->str_ptr;
  2044.     tlen = tstr->str_cur;
  2045.  
  2046.     if (s[-1] == *start)
  2047.     s--;
  2048.  
  2049.     s = scanstr(s, SCAN_TR|SCAN_REPL);
  2050.     if (s >= bufend) {
  2051.     yyerror("Translation replacement not terminated");
  2052.     yylval.arg = Nullarg;
  2053.     return s;
  2054.     }
  2055.     rstr = yylval.arg[1].arg_ptr.arg_str; 
  2056.     yylval.arg[1].arg_ptr.arg_str = Nullstr; 
  2057.     arg_free(yylval.arg);
  2058.     r = rstr->str_ptr;
  2059.     rlen = rstr->str_cur;
  2060.  
  2061.     complement = delete = squash = 0;
  2062.     while (*s == 'c' || *s == 'd' || *s == 's') {
  2063.     if (*s == 'c')
  2064.         complement = 1;
  2065.     else if (*s == 'd')
  2066.         delete = 2;
  2067.     else
  2068.         squash = 1;
  2069.     s++;
  2070.     }
  2071.     arg[2].arg_len = delete|squash;
  2072.     yylval.arg = arg;
  2073.     if (complement) {
  2074.     Zero(tbl, 256, short);
  2075.     for (i = 0; i < tlen; i++)
  2076.         tbl[t[i] & 0377] = -1;
  2077.     for (i = 0, j = 0; i < 256; i++) {
  2078.         if (!tbl[i]) {
  2079.         if (j >= rlen) {
  2080.             if (delete)
  2081.             tbl[i] = -2;
  2082.             else if (rlen)
  2083.             tbl[i] = r[j-1] & 0377;
  2084.             else
  2085.             tbl[i] = i;
  2086.         }
  2087.         else
  2088.             tbl[i] = r[j++] & 0377;
  2089.         }
  2090.     }
  2091.     }
  2092.     else {
  2093.     if (!rlen && !delete) {
  2094.         r = t; rlen = tlen;
  2095.     }
  2096.     for (i = 0; i < 256; i++)
  2097.         tbl[i] = -1;
  2098.     for (i = 0, j = 0; i < tlen; i++,j++) {
  2099.         if (j >= rlen) {
  2100.         if (delete) {
  2101.             if (tbl[t[i] & 0377] == -1)
  2102.             tbl[t[i] & 0377] = -2;
  2103.             continue;
  2104.         }
  2105.         --j;
  2106.         }
  2107.         if (tbl[t[i] & 0377] == -1)
  2108.         tbl[t[i] & 0377] = r[j] & 0377;
  2109.     }
  2110.     }
  2111.     str_free(tstr);
  2112.     str_free(rstr);
  2113.     return s;
  2114. }
  2115.  
  2116. char *
  2117. scanstr(start, in_what)
  2118. char *start;
  2119. int in_what;
  2120. {
  2121.     register char *s = start;
  2122.     register char term;
  2123.     register char *d;
  2124.     register ARG *arg;
  2125.     register char *send;
  2126.     register bool makesingle = FALSE;
  2127.     register STAB *stab;
  2128.     bool alwaysdollar = FALSE;
  2129.     bool hereis = FALSE;
  2130.     STR *herewas;
  2131.     STR *str;
  2132.     /* which backslash sequences to keep */
  2133.     char *leave = (in_what & SCAN_TR)
  2134.     ? "\\$@nrtfbeacx0123456789-"
  2135.     : "\\$@nrtfbeacx0123456789[{]}lLuUE";
  2136.     int len;
  2137.  
  2138.     arg = op_new(1);
  2139.     yylval.arg = arg;
  2140.     arg->arg_type = O_ITEM;
  2141.  
  2142.     switch (*s) {
  2143.     default:            /* a substitution replacement */
  2144.     arg[1].arg_type = A_DOUBLE;
  2145.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2146.     term = *s;
  2147.     if (term == '\'')
  2148.         leave = Nullch;
  2149.     goto snarf_it;
  2150.     case '0':
  2151.     {
  2152.         unsigned long i;
  2153.         int shift;
  2154.  
  2155.         arg[1].arg_type = A_SINGLE;
  2156.         if (s[1] == 'x') {
  2157.         shift = 4;
  2158.         s += 2;
  2159.         }
  2160.         else if (s[1] == '.')
  2161.         goto decimal;
  2162.         else
  2163.         shift = 3;
  2164.         i = 0;
  2165.         for (;;) {
  2166.         switch (*s) {
  2167.         default:
  2168.             goto out;
  2169.         case '_':
  2170.             s++;
  2171.             break;
  2172.         case '8': case '9':
  2173.             if (shift != 4)
  2174.             yyerror("Illegal octal digit");
  2175.             /* FALL THROUGH */
  2176.         case '0': case '1': case '2': case '3': case '4':
  2177.         case '5': case '6': case '7':
  2178.             i <<= shift;
  2179.             i += *s++ & 15;
  2180.             break;
  2181.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  2182.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  2183.             if (shift != 4)
  2184.             goto out;
  2185.             i <<= 4;
  2186.             i += (*s++ & 7) + 9;
  2187.             break;
  2188.         }
  2189.         }
  2190.       out:
  2191.         str = Str_new(92,0);
  2192.         str_numset(str,(double)i);
  2193.         if (str->str_ptr) {
  2194.         Safefree(str->str_ptr);
  2195.         str->str_ptr = Nullch;
  2196.         str->str_len = str->str_cur = 0;
  2197.         }
  2198.         arg[1].arg_ptr.arg_str = str;
  2199.     }
  2200.     break;
  2201.     case '1': case '2': case '3': case '4': case '5':
  2202.     case '6': case '7': case '8': case '9': case '.':
  2203.       decimal:
  2204.     arg[1].arg_type = A_SINGLE;
  2205.     d = tokenbuf;
  2206.     while (isDIGIT(*s) || *s == '_') {
  2207.         if (*s == '_')
  2208.         s++;
  2209.         else
  2210.         *d++ = *s++;
  2211.     }
  2212.     if (*s == '.' && s[1] != '.') {
  2213.         *d++ = *s++;
  2214.         while (isDIGIT(*s) || *s == '_') {
  2215.         if (*s == '_')
  2216.             s++;
  2217.         else
  2218.             *d++ = *s++;
  2219.         }
  2220.     }
  2221.     if (*s && index("eE",*s) && index("+-0123456789",s[1])) {
  2222.         *d++ = *s++;
  2223.         if (*s == '+' || *s == '-')
  2224.         *d++ = *s++;
  2225.         while (isDIGIT(*s))
  2226.         *d++ = *s++;
  2227.     }
  2228.     *d = '\0';
  2229.     str = Str_new(92,0);
  2230.     str_numset(str,atof(tokenbuf));
  2231.     if (str->str_ptr) {
  2232.         Safefree(str->str_ptr);
  2233.         str->str_ptr = Nullch;
  2234.         str->str_len = str->str_cur = 0;
  2235.     }
  2236.     arg[1].arg_ptr.arg_str = str;
  2237.     break;
  2238.     case '<':
  2239.     if (in_what & (SCAN_REPL|SCAN_TR))
  2240.         goto do_double;
  2241.     if (*++s == '<') {
  2242.         hereis = TRUE;
  2243.         d = tokenbuf;
  2244.         if (!rsfp)
  2245.         *d++ = '\n';
  2246.         if (*++s && index("`'\"",*s)) {
  2247.         term = *s++;
  2248.         s = cpytill(d,s,bufend,term,&len);
  2249.         if (s < bufend)
  2250.             s++;
  2251.         d += len;
  2252.         }
  2253.         else {
  2254.         if (*s == '\\')
  2255.             s++, term = '\'';
  2256.         else
  2257.             term = '"';
  2258.         while (isALNUM(*s))
  2259.             *d++ = *s++;
  2260.         }                /* assuming tokenbuf won't clobber */
  2261.         *d++ = '\n';
  2262.         *d = '\0';
  2263.         len = d - tokenbuf;
  2264.         d = "\n";
  2265.         if (rsfp || !(d=ninstr(s,bufend,d,d+1)))
  2266.         herewas = str_make(s,bufend-s);
  2267.         else
  2268.         s--, herewas = str_make(s,d-s);
  2269.         s += herewas->str_cur;
  2270.         if (term == '\'')
  2271.         goto do_single;
  2272.         if (term == '`')
  2273.         goto do_back;
  2274.         goto do_double;
  2275.     }
  2276.     d = tokenbuf;
  2277.     s = cpytill(d,s,bufend,'>',&len);
  2278.     if (s < bufend)
  2279.         s++;
  2280.     else
  2281.         fatal("Unterminated <> operator");
  2282.  
  2283.     if (*d == '$') d++;
  2284.     while (*d && (isALNUM(*d) || *d == '\''))
  2285.         d++;
  2286.     if (d - tokenbuf != len) {
  2287.         s = start;
  2288.         term = *s;
  2289.         arg[1].arg_type = A_GLOB;
  2290.         set_csh();
  2291.         alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2292.         goto snarf_it;
  2293.     }
  2294.     else {
  2295.         d = tokenbuf;
  2296.         if (!len)
  2297.         (void)strcpy(d,"ARGV");
  2298.         if (*d == '$') {
  2299.         arg[1].arg_type = A_INDREAD;
  2300.         arg[1].arg_ptr.arg_stab = stabent(d+1,TRUE);
  2301.         }
  2302.         else {
  2303.         arg[1].arg_type = A_READ;
  2304.         arg[1].arg_ptr.arg_stab = stabent(d,TRUE);
  2305.         if (!stab_io(arg[1].arg_ptr.arg_stab))
  2306.             stab_io(arg[1].arg_ptr.arg_stab) = stio_new();
  2307.         if (strEQ(d,"ARGV")) {
  2308.             (void)aadd(arg[1].arg_ptr.arg_stab);
  2309.             stab_io(arg[1].arg_ptr.arg_stab)->flags |=
  2310.               IOF_ARGV|IOF_START;
  2311.         }
  2312.         }
  2313.     }
  2314.     break;
  2315.  
  2316.     case 'q':
  2317.     s++;
  2318.     if (*s == 'q') {
  2319.         s++;
  2320.         goto do_double;
  2321.     }
  2322.     if (*s == 'x') {
  2323.         s++;
  2324.         goto do_back;
  2325.     }
  2326.     /* FALL THROUGH */
  2327.     case '\'':
  2328.       do_single:
  2329.     term = *s;
  2330.     arg[1].arg_type = A_SINGLE;
  2331.     leave = Nullch;
  2332.     goto snarf_it;
  2333.  
  2334.     case '"': 
  2335.       do_double:
  2336.     term = *s;
  2337.     arg[1].arg_type = A_DOUBLE;
  2338.     makesingle = TRUE;    /* maybe disable runtime scanning */
  2339.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2340.     goto snarf_it;
  2341.     case '`':
  2342.       do_back:
  2343.     term = *s;
  2344.     arg[1].arg_type = A_BACKTICK;
  2345.     set_csh();
  2346.     alwaysdollar = TRUE;    /* treat $) and $| as variables */
  2347.       snarf_it:
  2348.     {
  2349.         STR *tmpstr;
  2350.         STR *tmpstr2 = Nullstr;
  2351.         char *tmps;
  2352.         char *start;
  2353.         bool dorange = FALSE;
  2354.  
  2355.         CLINE;
  2356.         multi_start = curcmd->c_line;
  2357.         if (hereis)
  2358.         multi_open = multi_close = '<';
  2359.         else {
  2360.         multi_open = term;
  2361.         if (term && (tmps = index("([{< )]}> )]}>",term)))
  2362.             term = tmps[5];
  2363.         multi_close = term;
  2364.         }
  2365.         tmpstr = Str_new(87,80);
  2366.         if (hereis) {
  2367.         term = *tokenbuf;
  2368.         if (!rsfp) {
  2369.             d = s;
  2370.             while (s < bufend &&
  2371.               (*s != term || bcmp(s,tokenbuf,len) != 0) ) {
  2372.             if (*s++ == '\n')
  2373.                 curcmd->c_line++;
  2374.             }
  2375.             if (s >= bufend) {
  2376.             curcmd->c_line = multi_start;
  2377.             fatal("EOF in string");
  2378.             }
  2379.             str_nset(tmpstr,d+1,s-d);
  2380.             s += len - 1;
  2381.             str_ncat(herewas,s,bufend-s);
  2382.             str_replace(linestr,herewas);
  2383.             oldoldbufptr = oldbufptr = bufptr = s = str_get(linestr);
  2384.             bufend = linestr->str_ptr + linestr->str_cur;
  2385.             hereis = FALSE;
  2386.         }
  2387.         else
  2388.             str_nset(tmpstr,"",0);   /* avoid "uninitialized" warning */
  2389.         }
  2390.         else
  2391.         s = str_append_till(tmpstr,s+1,bufend,term,leave);
  2392.         while (s >= bufend) {    /* multiple line string? */
  2393.         if (!rsfp ||
  2394.          !(oldoldbufptr = oldbufptr = s = str_gets(linestr, rsfp, 0))) {
  2395.             curcmd->c_line = multi_start;
  2396.             fatal("EOF in string");
  2397.         }
  2398.         curcmd->c_line++;
  2399.         if (perldb) {
  2400.             STR *str = Str_new(88,0);
  2401.  
  2402.             str_sset(str,linestr);
  2403.             astore(stab_xarray(curcmd->c_filestab),
  2404.               (int)curcmd->c_line,str);
  2405.         }
  2406.         bufend = linestr->str_ptr + linestr->str_cur;
  2407.         if (hereis) {
  2408.             if (*s == term && bcmp(s,tokenbuf,len) == 0) {
  2409.             s = bufend - 1;
  2410.             *s = ' ';
  2411.             str_scat(linestr,herewas);
  2412.             bufend = linestr->str_ptr + linestr->str_cur;
  2413.             }
  2414.             else {
  2415.             s = bufend;
  2416.             str_scat(tmpstr,linestr);
  2417.             }
  2418.         }
  2419.         else
  2420.             s = str_append_till(tmpstr,s,bufend,term,leave);
  2421.         }
  2422.         multi_end = curcmd->c_line;
  2423.         s++;
  2424.         if (tmpstr->str_cur + 5 < tmpstr->str_len) {
  2425.         tmpstr->str_len = tmpstr->str_cur + 1;
  2426.         Renew(tmpstr->str_ptr, tmpstr->str_len, char);
  2427.         }
  2428.         if (arg[1].arg_type == A_SINGLE) {
  2429.         arg[1].arg_ptr.arg_str = tmpstr;
  2430.         break;
  2431.         }
  2432.         tmps = s;
  2433.         s = tmpstr->str_ptr;
  2434.         send = s + tmpstr->str_cur;
  2435.         while (s < send) {        /* see if we can make SINGLE */
  2436.         if (*s == '\\' && s[1] && isDIGIT(s[1]) && !isDIGIT(s[2]) &&
  2437.           !alwaysdollar && s[1] != '0')
  2438.             *s = '$';        /* grandfather \digit in subst */
  2439.         if ((*s == '$' || *s == '@') && s+1 < send &&
  2440.           (alwaysdollar || (s[1] != ')' && s[1] != '|'))) {
  2441.             makesingle = FALSE;    /* force interpretation */
  2442.         }
  2443.         else if (*s == '\\' && s+1 < send) {
  2444.             if (index("lLuUE",s[1]))
  2445.             makesingle = FALSE;
  2446.             s++;
  2447.         }
  2448.         s++;
  2449.         }
  2450.         s = d = start = tmpstr->str_ptr;    /* assuming shrinkage only */
  2451.         while (s < send || dorange) {
  2452.         if (in_what & SCAN_TR) {
  2453.             if (dorange) {
  2454.             int i;
  2455.             int max;
  2456.             if (!tmpstr2) {    /* oops, have to grow */
  2457.                 tmpstr2 = str_smake(tmpstr);
  2458.                 s = tmpstr2->str_ptr + (s - tmpstr->str_ptr);
  2459.                 send = tmpstr2->str_ptr + (send - tmpstr->str_ptr);
  2460.             }
  2461.             i = d - tmpstr->str_ptr;
  2462.             STR_GROW(tmpstr, tmpstr->str_len + 256);
  2463.             d = tmpstr->str_ptr + i;
  2464.             d -= 2;
  2465.             max = d[1] & 0377;
  2466.             for (i = (*d & 0377); i <= max; i++)
  2467.                 *d++ = i;
  2468.             start = s;
  2469.             dorange = FALSE;
  2470.             continue;
  2471.             }
  2472.             else if (*s == '-' && s+1 < send  && s != start) {
  2473.             dorange = TRUE;
  2474.             s++;
  2475.             }
  2476.         }
  2477.         else {
  2478.             if ((*s == '$' && s+1 < send &&
  2479.             (alwaysdollar || /*(*/(s[1] != ')' && s[1] != '|')) ) ||
  2480.             (*s == '@' && s+1 < send) ) {
  2481.             if (s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  2482.                 *d++ = *s++;
  2483.             len = scanident(s,send,tokenbuf) - s;
  2484.             if (*s == '$' || strEQ(tokenbuf,"ARGV")
  2485.               || strEQ(tokenbuf,"ENV")
  2486.               || strEQ(tokenbuf,"SIG")
  2487.               || strEQ(tokenbuf,"INC") )
  2488.                 (void)stabent(tokenbuf,TRUE); /* add symbol */
  2489.             while (len--)
  2490.                 *d++ = *s++;
  2491.             continue;
  2492.             }
  2493.         }
  2494.         if (*s == '\\' && s+1 < send) {
  2495.             s++;
  2496.             switch (*s) {
  2497.             case '-':
  2498.             if (in_what & SCAN_TR) {
  2499.                 *d++ = *s++;
  2500.                 continue;
  2501.             }
  2502.             /* FALL THROUGH */
  2503.             default:
  2504.             if (!makesingle && (!leave || (*s && index(leave,*s))))
  2505.                 *d++ = '\\';
  2506.             *d++ = *s++;
  2507.             continue;
  2508.             case '0': case '1': case '2': case '3':
  2509.             case '4': case '5': case '6': case '7':
  2510.             *d++ = scanoct(s, 3, &len);
  2511.             s += len;
  2512.             continue;
  2513.             case 'x':
  2514.             *d++ = scanhex(++s, 2, &len);
  2515.             s += len;
  2516.             continue;
  2517.             case 'c':
  2518.             s++;
  2519.             *d = *s++;
  2520.             if (isLOWER(*d))
  2521.                 *d = toupper(*d);
  2522.             *d++ ^= 64;
  2523.             continue;
  2524.             case 'b':
  2525.             *d++ = '\b';
  2526.             break;
  2527.             case 'n':
  2528.             *d++ = '\n';
  2529.             break;
  2530.             case 'r':
  2531.             *d++ = '\r';
  2532.             break;
  2533.             case 'f':
  2534.             *d++ = '\f';
  2535.             break;
  2536.             case 't':
  2537.             *d++ = '\t';
  2538.             break;
  2539.             case 'e':
  2540.             *d++ = '\033';
  2541.             break;
  2542.             case 'a':
  2543.             *d++ = '\007';
  2544.             break;
  2545.             }
  2546.             s++;
  2547.             continue;
  2548.         }
  2549.         *d++ = *s++;
  2550.         }
  2551.         *d = '\0';
  2552.  
  2553.         if (arg[1].arg_type == A_DOUBLE && makesingle)
  2554.         arg[1].arg_type = A_SINGLE;    /* now we can optimize on it */
  2555.  
  2556.         tmpstr->str_cur = d - tmpstr->str_ptr;
  2557.         if (arg[1].arg_type == A_GLOB) {
  2558.         arg[1].arg_ptr.arg_stab = stab = genstab();
  2559.         stab_io(stab) = stio_new();
  2560.         str_sset(stab_val(stab), tmpstr);
  2561.         }
  2562.         else
  2563.         arg[1].arg_ptr.arg_str = tmpstr;
  2564.         s = tmps;
  2565.         if (tmpstr2)
  2566.         str_free(tmpstr2);
  2567.         break;
  2568.     }
  2569.     }
  2570.     if (hereis)
  2571.     str_free(herewas);
  2572.     return s;
  2573. }
  2574.  
  2575. FCMD *
  2576. load_format()
  2577. {
  2578.     FCMD froot;
  2579.     FCMD *flinebeg;
  2580.     char *eol;
  2581.     register FCMD *fprev = &froot;
  2582.     register FCMD *fcmd;
  2583.     register char *s;
  2584.     register char *t;
  2585.     register STR *str;
  2586.     bool noblank;
  2587.     bool repeater;
  2588.  
  2589.     Zero(&froot, 1, FCMD);
  2590.     s = bufptr;
  2591.     while (s < bufend || (rsfp && (s = str_gets(linestr,rsfp, 0)) != Nullch)) {
  2592.     curcmd->c_line++;
  2593.     if (in_eval && !rsfp) {
  2594.         eol = index(s,'\n');
  2595.         if (!eol++)
  2596.         eol = bufend;
  2597.     }
  2598.     else
  2599.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2600.     if (perldb) {
  2601.         STR *tmpstr = Str_new(89,0);
  2602.  
  2603.         str_nset(tmpstr, s, eol-s);
  2604.         astore(stab_xarray(curcmd->c_filestab), (int)curcmd->c_line,tmpstr);
  2605.     }
  2606.     if (*s == '.') {
  2607.         /*SUPPRESS 530*/
  2608.         for (t = s+1; *t == ' ' || *t == '\t'; t++) ;
  2609.         if (*t == '\n') {
  2610.         bufptr = s;
  2611.         return froot.f_next;
  2612.         }
  2613.     }
  2614.     if (*s == '#') {
  2615.         s = eol;
  2616.         continue;
  2617.     }
  2618.     flinebeg = Nullfcmd;
  2619.     noblank = FALSE;
  2620.     repeater = FALSE;
  2621.     while (s < eol) {
  2622.         Newz(804,fcmd,1,FCMD);
  2623.         fprev->f_next = fcmd;
  2624.         fprev = fcmd;
  2625.         for (t=s; t < eol && *t != '@' && *t != '^'; t++) {
  2626.         if (*t == '~') {
  2627.             noblank = TRUE;
  2628.             *t = ' ';
  2629.             if (t[1] == '~') {
  2630.             repeater = TRUE;
  2631.             t[1] = ' ';
  2632.             }
  2633.         }
  2634.         }
  2635.         fcmd->f_pre = nsavestr(s, t-s);
  2636.         fcmd->f_presize = t-s;
  2637.         s = t;
  2638.         if (s >= eol) {
  2639.         if (noblank)
  2640.             fcmd->f_flags |= FC_NOBLANK;
  2641.         if (repeater)
  2642.             fcmd->f_flags |= FC_REPEAT;
  2643.         break;
  2644.         }
  2645.         if (!flinebeg)
  2646.         flinebeg = fcmd;        /* start values here */
  2647.         if (*s++ == '^')
  2648.         fcmd->f_flags |= FC_CHOP;    /* for doing text filling */
  2649.         switch (*s) {
  2650.         case '*':
  2651.         fcmd->f_type = F_LINES;
  2652.         *s = '\0';
  2653.         break;
  2654.         case '<':
  2655.         fcmd->f_type = F_LEFT;
  2656.         while (*s == '<')
  2657.             s++;
  2658.         break;
  2659.         case '>':
  2660.         fcmd->f_type = F_RIGHT;
  2661.         while (*s == '>')
  2662.             s++;
  2663.         break;
  2664.         case '|':
  2665.         fcmd->f_type = F_CENTER;
  2666.         while (*s == '|')
  2667.             s++;
  2668.         break;
  2669.         case '#':
  2670.         case '.':
  2671.         /* Catch the special case @... and handle it as a string
  2672.            field. */
  2673.         if (*s == '.' && s[1] == '.') {
  2674.             goto default_format;
  2675.         }
  2676.         fcmd->f_type = F_DECIMAL;
  2677.         {
  2678.             char *p;
  2679.  
  2680.             /* Read a format in the form @####.####, where either group
  2681.                of ### may be empty, or the final .### may be missing. */
  2682.             while (*s == '#')
  2683.             s++;
  2684.             if (*s == '.') {
  2685.             s++;
  2686.             p = s;
  2687.             while (*s == '#')
  2688.                 s++;
  2689.             fcmd->f_decimals = s-p;
  2690.             fcmd->f_flags |= FC_DP;
  2691.             } else {
  2692.             fcmd->f_decimals = 0;
  2693.             }
  2694.         }
  2695.         break;
  2696.         default:
  2697.         default_format:
  2698.         fcmd->f_type = F_LEFT;
  2699.         break;
  2700.         }
  2701.         if (fcmd->f_flags & FC_CHOP && *s == '.') {
  2702.         fcmd->f_flags |= FC_MORE;
  2703.         while (*s == '.')
  2704.             s++;
  2705.         }
  2706.         fcmd->f_size = s-t;
  2707.     }
  2708.     if (flinebeg) {
  2709.       again:
  2710.         if (s >= bufend &&
  2711.           (!rsfp || (s = str_gets(linestr, rsfp, 0)) == Nullch) )
  2712.         goto badform;
  2713.         curcmd->c_line++;
  2714.         if (in_eval && !rsfp) {
  2715.         eol = index(s,'\n');
  2716.         if (!eol++)
  2717.             eol = bufend;
  2718.         }
  2719.         else
  2720.         eol = bufend = linestr->str_ptr + linestr->str_cur;
  2721.         if (perldb) {
  2722.         STR *tmpstr = Str_new(90,0);
  2723.  
  2724.         str_nset(tmpstr, s, eol-s);
  2725.         astore(stab_xarray(curcmd->c_filestab),
  2726.             (int)curcmd->c_line,tmpstr);
  2727.         }
  2728.         if (strnEQ(s,".\n",2)) {
  2729.         bufptr = s;
  2730.         yyerror("Missing values line");
  2731.         return froot.f_next;
  2732.         }
  2733.         if (*s == '#') {
  2734.         s = eol;
  2735.         goto again;
  2736.         }
  2737.         str = flinebeg->f_unparsed = Str_new(91,eol - s);
  2738.         str->str_u.str_hash = curstash;
  2739.         str_nset(str,"(",1);
  2740.         flinebeg->f_line = curcmd->c_line;
  2741.         eol[-1] = '\0';
  2742.         if (!flinebeg->f_next->f_type || index(s, ',')) {
  2743.         eol[-1] = '\n';
  2744.         str_ncat(str, s, eol - s - 1);
  2745.         str_ncat(str,",$$);",5);
  2746.         s = eol;
  2747.         }
  2748.         else {
  2749.         eol[-1] = '\n';
  2750.         while (s < eol && isSPACE(*s))
  2751.             s++;
  2752.         t = s;
  2753.         while (s < eol) {
  2754.             switch (*s) {
  2755.             case ' ': case '\t': case '\n': case ';':
  2756.             str_ncat(str, t, s - t);
  2757.             str_ncat(str, "," ,1);
  2758.             while (s < eol && (isSPACE(*s) || *s == ';'))
  2759.                 s++;
  2760.             t = s;
  2761.             break;
  2762.             case '$':
  2763.             str_ncat(str, t, s - t);
  2764.             t = s;
  2765.             s = scanident(s,eol,tokenbuf);
  2766.             str_ncat(str, t, s - t);
  2767.             t = s;
  2768.             if (s < eol && *s && index("$'\"",*s))
  2769.                 str_ncat(str, ",", 1);
  2770.             break;
  2771.             case '"': case '\'':
  2772.             str_ncat(str, t, s - t);
  2773.             t = s;
  2774.             s++;
  2775.             while (s < eol && (*s != *t || s[-1] == '\\'))
  2776.                 s++;
  2777.             if (s < eol)
  2778.                 s++;
  2779.             str_ncat(str, t, s - t);
  2780.             t = s;
  2781.             if (s < eol && *s && index("$'\"",*s))
  2782.                 str_ncat(str, ",", 1);
  2783.             break;
  2784.             default:
  2785.             yyerror("Please use commas to separate fields");
  2786.             }
  2787.         }
  2788.         str_ncat(str,"$$);",4);
  2789.         }
  2790.     }
  2791.     }
  2792.   badform:
  2793.     bufptr = str_get(linestr);
  2794.     yyerror("Format not terminated");
  2795.     return froot.f_next;
  2796. }
  2797.  
  2798. static void
  2799. set_csh()
  2800. {
  2801. #ifdef CSH
  2802.     if (!cshlen)
  2803.     cshlen = strlen(cshname);
  2804. #endif
  2805. }
  2806.  
  2807. void init_toke()
  2808. {
  2809.     reparse = NULL;
  2810.     last_uni= NULL;
  2811. }